]> git.proxmox.com Git - mirror_frr.git/blob - ripd/rip_peer.c
Merge pull request #13246 from opensourcerouting/rip-bfd
[mirror_frr.git] / ripd / rip_peer.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* RIP peer support
3 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
4 */
5
6 #include <zebra.h>
7
8 #include "if.h"
9 #include "prefix.h"
10 #include "command.h"
11 #include "linklist.h"
12 #include "frrevent.h"
13 #include "memory.h"
14 #include "table.h"
15
16 #include "ripd/ripd.h"
17 #include "ripd/rip_bfd.h"
18
19 DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer");
20
21 static struct rip_peer *rip_peer_new(void)
22 {
23 return XCALLOC(MTYPE_RIP_PEER, sizeof(struct rip_peer));
24 }
25
26 void rip_peer_free(struct rip_peer *peer)
27 {
28 bfd_sess_free(&peer->bfd_session);
29 EVENT_OFF(peer->t_timeout);
30 XFREE(MTYPE_RIP_PEER, peer);
31 }
32
33 struct rip_peer *rip_peer_lookup(struct rip *rip, struct in_addr *addr)
34 {
35 struct rip_peer *peer;
36 struct listnode *node, *nnode;
37
38 for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
39 if (IPV4_ADDR_SAME(&peer->addr, addr))
40 return peer;
41 }
42 return NULL;
43 }
44
45 struct rip_peer *rip_peer_lookup_next(struct rip *rip, struct in_addr *addr)
46 {
47 struct rip_peer *peer;
48 struct listnode *node, *nnode;
49
50 for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
51 if (htonl(peer->addr.s_addr) > htonl(addr->s_addr))
52 return peer;
53 }
54 return NULL;
55 }
56
57 /* RIP peer is timeout. */
58 static void rip_peer_timeout(struct event *t)
59 {
60 struct rip_peer *peer;
61
62 peer = EVENT_ARG(t);
63 listnode_delete(peer->rip->peer_list, peer);
64 rip_peer_free(peer);
65 }
66
67 /* Get RIP peer. At the same time update timeout thread. */
68 static struct rip_peer *rip_peer_get(struct rip *rip, struct rip_interface *ri,
69 struct in_addr *addr)
70 {
71 struct rip_peer *peer;
72
73 peer = rip_peer_lookup(rip, addr);
74
75 if (peer) {
76 EVENT_OFF(peer->t_timeout);
77 } else {
78 peer = rip_peer_new();
79 peer->rip = rip;
80 peer->ri = ri;
81 peer->addr = *addr;
82 rip_bfd_session_update(peer);
83 listnode_add_sort(rip->peer_list, peer);
84 }
85
86 /* Update timeout thread. */
87 event_add_timer(master, rip_peer_timeout, peer, RIP_PEER_TIMER_DEFAULT,
88 &peer->t_timeout);
89
90 /* Last update time set. */
91 time(&peer->uptime);
92
93 return peer;
94 }
95
96 void rip_peer_update(struct rip *rip, struct rip_interface *ri,
97 struct sockaddr_in *from, uint8_t version)
98 {
99 struct rip_peer *peer;
100 peer = rip_peer_get(rip, ri, &from->sin_addr);
101 peer->version = version;
102 }
103
104 void rip_peer_bad_route(struct rip *rip, struct rip_interface *ri,
105 struct sockaddr_in *from)
106 {
107 struct rip_peer *peer;
108 peer = rip_peer_get(rip, ri, &from->sin_addr);
109 peer->recv_badroutes++;
110 }
111
112 void rip_peer_bad_packet(struct rip *rip, struct rip_interface *ri,
113 struct sockaddr_in *from)
114 {
115 struct rip_peer *peer;
116 peer = rip_peer_get(rip, ri, &from->sin_addr);
117 peer->recv_badpackets++;
118 }
119
120 /* Display peer uptime. */
121 static char *rip_peer_uptime(struct rip_peer *peer, char *buf, size_t len)
122 {
123 time_t uptime;
124
125 /* If there is no connection has been done before print `never'. */
126 if (peer->uptime == 0) {
127 snprintf(buf, len, "never ");
128 return buf;
129 }
130
131 /* Get current time. */
132 uptime = time(NULL);
133 uptime -= peer->uptime;
134
135 frrtime_to_interval(uptime, buf, len);
136
137 return buf;
138 }
139
140 void rip_peer_display(struct vty *vty, struct rip *rip)
141 {
142 struct rip_peer *peer;
143 struct listnode *node, *nnode;
144 #define RIP_UPTIME_LEN 25
145 char timebuf[RIP_UPTIME_LEN];
146
147 for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
148 vty_out(vty, " %-17pI4 %9d %9d %9d %11s\n",
149 &peer->addr, peer->recv_badpackets,
150 peer->recv_badroutes, ZEBRA_RIP_DISTANCE_DEFAULT,
151 rip_peer_uptime(peer, timebuf, RIP_UPTIME_LEN));
152 }
153 }
154
155 int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2)
156 {
157 if (p2->addr.s_addr == p1->addr.s_addr)
158 return 0;
159
160 return (htonl(p1->addr.s_addr) < htonl(p2->addr.s_addr)) ? -1 : 1;
161 }
162
163 void rip_peer_list_del(void *arg)
164 {
165 rip_peer_free(arg);
166 }
167
168 void rip_peer_delete_routes(const struct rip_peer *peer)
169 {
170 struct route_node *route_node;
171
172 for (route_node = route_top(peer->rip->table); route_node;
173 route_node = route_next(route_node)) {
174 struct rip_info *route_entry;
175 struct listnode *listnode;
176 struct listnode *listnode_next;
177 struct list *list;
178
179 list = route_node->info;
180 if (list == NULL)
181 continue;
182
183 for (ALL_LIST_ELEMENTS(list, listnode, listnode_next,
184 route_entry)) {
185 if (!rip_route_rte(route_entry))
186 continue;
187 if (route_entry->from.s_addr != peer->addr.s_addr)
188 continue;
189
190 if (listcount(list) == 1) {
191 EVENT_OFF(route_entry->t_timeout);
192 EVENT_OFF(route_entry->t_garbage_collect);
193 listnode_delete(list, route_entry);
194 if (list_isempty(list)) {
195 list_delete((struct list **)&route_node
196 ->info);
197 route_unlock_node(route_node);
198 }
199 rip_info_free(route_entry);
200
201 /* Signal the output process to trigger an
202 * update (see section 2.5). */
203 rip_event(peer->rip, RIP_TRIGGERED_UPDATE, 0);
204 } else
205 rip_ecmp_delete(peer->rip, route_entry);
206 break;
207 }
208 }
209 }