]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_neighbor.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / eigrpd / eigrp_neighbor.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * EIGRP Neighbor Handling.
4 * Copyright (C) 2013-2016
5 * Authors:
6 * Donnie Savage
7 * Jan Janovic
8 * Matej Perina
9 * Peter Orsag
10 * Peter Paluch
11 * Frantisek Gazo
12 * Tomas Hvorkovy
13 * Martin Kontsek
14 * Lukas Koribsky
15 */
16
17 #include <zebra.h>
18
19 #include "linklist.h"
20 #include "prefix.h"
21 #include "memory.h"
22 #include "command.h"
23 #include "thread.h"
24 #include "stream.h"
25 #include "table.h"
26 #include "log.h"
27 #include "keychain.h"
28 #include "vty.h"
29
30 #include "eigrpd/eigrp_structs.h"
31 #include "eigrpd/eigrpd.h"
32 #include "eigrpd/eigrp_interface.h"
33 #include "eigrpd/eigrp_neighbor.h"
34 #include "eigrpd/eigrp_dump.h"
35 #include "eigrpd/eigrp_packet.h"
36 #include "eigrpd/eigrp_zebra.h"
37 #include "eigrpd/eigrp_vty.h"
38 #include "eigrpd/eigrp_network.h"
39 #include "eigrpd/eigrp_topology.h"
40 #include "eigrpd/eigrp_errors.h"
41
42 DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor");
43
44 struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei)
45 {
46 struct eigrp_neighbor *nbr;
47
48 /* Allcate new neighbor. */
49 nbr = XCALLOC(MTYPE_EIGRP_NEIGHBOR, sizeof(struct eigrp_neighbor));
50
51 /* Relate neighbor to the interface. */
52 nbr->ei = ei;
53
54 /* Set default values. */
55 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
56
57 return nbr;
58 }
59
60 /**
61 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
62 * proto_item *ti)
63 *
64 * @par
65 * Create a new neighbor structure and initalize it.
66 */
67 static struct eigrp_neighbor *eigrp_nbr_add(struct eigrp_interface *ei,
68 struct eigrp_header *eigrph,
69 struct ip *iph)
70 {
71 struct eigrp_neighbor *nbr;
72
73 nbr = eigrp_nbr_new(ei);
74 nbr->src = iph->ip_src;
75
76 return nbr;
77 }
78
79 struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *ei,
80 struct eigrp_header *eigrph,
81 struct ip *iph)
82 {
83 struct eigrp_neighbor *nbr;
84 struct listnode *node, *nnode;
85
86 for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
87 if (iph->ip_src.s_addr == nbr->src.s_addr) {
88 return nbr;
89 }
90 }
91
92 nbr = eigrp_nbr_add(ei, eigrph, iph);
93 listnode_add(ei->nbrs, nbr);
94
95 return nbr;
96 }
97
98 /**
99 * @fn eigrp_nbr_lookup_by_addr
100 *
101 * @param[in] ei EIGRP interface
102 * @param[in] nbr_addr Address of neighbor
103 *
104 * @return void
105 *
106 * @par
107 * Function is used for neighbor lookup by address
108 * in specified interface.
109 */
110 struct eigrp_neighbor *eigrp_nbr_lookup_by_addr(struct eigrp_interface *ei,
111 struct in_addr *addr)
112 {
113 struct eigrp_neighbor *nbr;
114 struct listnode *node, *nnode;
115
116 for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
117 if (addr->s_addr == nbr->src.s_addr) {
118 return nbr;
119 }
120 }
121
122 return NULL;
123 }
124
125 /**
126 * @fn eigrp_nbr_lookup_by_addr_process
127 *
128 * @param[in] eigrp EIGRP process
129 * @param[in] nbr_addr Address of neighbor
130 *
131 * @return void
132 *
133 * @par
134 * Function is used for neighbor lookup by address
135 * in whole EIGRP process.
136 */
137 struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp,
138 struct in_addr nbr_addr)
139 {
140 struct eigrp_interface *ei;
141 struct listnode *node, *node2, *nnode2;
142 struct eigrp_neighbor *nbr;
143
144 /* iterate over all eigrp interfaces */
145 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
146 /* iterate over all neighbors on eigrp interface */
147 for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) {
148 /* compare if neighbor address is same as arg address */
149 if (nbr->src.s_addr == nbr_addr.s_addr) {
150 return nbr;
151 }
152 }
153 }
154
155 return NULL;
156 }
157
158
159 /* Delete specified EIGRP neighbor from interface. */
160 void eigrp_nbr_delete(struct eigrp_neighbor *nbr)
161 {
162 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
163 if (nbr->ei)
164 eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
165
166 /* Cancel all events. */ /* Thread lookup cost would be negligible. */
167 thread_cancel_event(master, nbr);
168 eigrp_fifo_free(nbr->multicast_queue);
169 eigrp_fifo_free(nbr->retrans_queue);
170 THREAD_OFF(nbr->t_holddown);
171
172 if (nbr->ei)
173 listnode_delete(nbr->ei->nbrs, nbr);
174 XFREE(MTYPE_EIGRP_NEIGHBOR, nbr);
175 }
176
177 void holddown_timer_expired(struct thread *thread)
178 {
179 struct eigrp_neighbor *nbr = THREAD_ARG(thread);
180 struct eigrp *eigrp = nbr->ei->eigrp;
181
182 zlog_info("Neighbor %pI4 (%s) is down: holding time expired", &nbr->src,
183 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
184 nbr->state = EIGRP_NEIGHBOR_DOWN;
185 eigrp_nbr_delete(nbr);
186 }
187
188 uint8_t eigrp_nbr_state_get(struct eigrp_neighbor *nbr)
189 {
190 return (nbr->state);
191 }
192
193 void eigrp_nbr_state_set(struct eigrp_neighbor *nbr, uint8_t state)
194 {
195 nbr->state = state;
196
197 if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN) {
198 // reset all the seq/ack counters
199 nbr->recv_sequence_number = 0;
200 nbr->init_sequence_number = 0;
201 nbr->retrans_counter = 0;
202
203 // Kvalues
204 nbr->K1 = EIGRP_K1_DEFAULT;
205 nbr->K2 = EIGRP_K2_DEFAULT;
206 nbr->K3 = EIGRP_K3_DEFAULT;
207 nbr->K4 = EIGRP_K4_DEFAULT;
208 nbr->K5 = EIGRP_K5_DEFAULT;
209 nbr->K6 = EIGRP_K6_DEFAULT;
210
211 // hold time..
212 nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT;
213 THREAD_OFF(nbr->t_holddown);
214
215 /* out with the old */
216 if (nbr->multicast_queue)
217 eigrp_fifo_free(nbr->multicast_queue);
218 if (nbr->retrans_queue)
219 eigrp_fifo_free(nbr->retrans_queue);
220
221 /* in with the new */
222 nbr->retrans_queue = eigrp_fifo_new();
223 nbr->multicast_queue = eigrp_fifo_new();
224
225 nbr->crypt_seqnum = 0;
226 }
227 }
228
229 const char *eigrp_nbr_state_str(struct eigrp_neighbor *nbr)
230 {
231 const char *state;
232 switch (nbr->state) {
233 case EIGRP_NEIGHBOR_DOWN:
234 state = "Down";
235 break;
236 case EIGRP_NEIGHBOR_PENDING:
237 state = "Waiting for Init";
238 break;
239 case EIGRP_NEIGHBOR_UP:
240 state = "Up";
241 break;
242 default:
243 state = "Unknown";
244 break;
245 }
246
247 return (state);
248 }
249
250 void eigrp_nbr_state_update(struct eigrp_neighbor *nbr)
251 {
252 switch (nbr->state) {
253 case EIGRP_NEIGHBOR_DOWN: {
254 /*Start Hold Down Timer for neighbor*/
255 // THREAD_OFF(nbr->t_holddown);
256 // THREAD_TIMER_ON(master, nbr->t_holddown,
257 // holddown_timer_expired,
258 // nbr, nbr->v_holddown);
259 break;
260 }
261 case EIGRP_NEIGHBOR_PENDING: {
262 /*Reset Hold Down Timer for neighbor*/
263 THREAD_OFF(nbr->t_holddown);
264 thread_add_timer(master, holddown_timer_expired, nbr,
265 nbr->v_holddown, &nbr->t_holddown);
266 break;
267 }
268 case EIGRP_NEIGHBOR_UP: {
269 /*Reset Hold Down Timer for neighbor*/
270 THREAD_OFF(nbr->t_holddown);
271 thread_add_timer(master, holddown_timer_expired, nbr,
272 nbr->v_holddown, &nbr->t_holddown);
273 break;
274 }
275 }
276 }
277
278 int eigrp_nbr_count_get(struct eigrp *eigrp)
279 {
280 struct eigrp_interface *iface;
281 struct listnode *node, *node2, *nnode2;
282 struct eigrp_neighbor *nbr;
283 uint32_t counter;
284
285 counter = 0;
286 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
287 for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr)) {
288 if (nbr->state == EIGRP_NEIGHBOR_UP) {
289 counter++;
290 }
291 }
292 }
293 return counter;
294 }
295
296 /**
297 * @fn eigrp_nbr_hard_restart
298 *
299 * @param[in] nbr Neighbor who would receive hard restart
300 * @param[in] vty Virtual terminal for log output
301 * @return void
302 *
303 * @par
304 * Function used for executing hard restart for neighbor:
305 * Send Hello packet with Peer Termination TLV with
306 * neighbor's address, set it's state to DOWN and delete the neighbor
307 */
308 void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
309 {
310 struct eigrp *eigrp = nbr->ei->eigrp;
311
312 zlog_debug("Neighbor %pI4 (%s) is down: manually cleared", &nbr->src,
313 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
314 if (vty != NULL) {
315 vty_time_print(vty, 0);
316 vty_out(vty, "Neighbor %pI4 (%s) is down: manually cleared\n",
317 &nbr->src,
318 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
319 }
320
321 /* send Hello with Peer Termination TLV */
322 eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR,
323 &(nbr->src));
324 /* set neighbor to DOWN */
325 nbr->state = EIGRP_NEIGHBOR_DOWN;
326 /* delete neighbor */
327 eigrp_nbr_delete(nbr);
328 }
329
330 int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
331 struct eigrp_interface *ei)
332 {
333 if (ne->distance == EIGRP_MAX_METRIC)
334 return 0;
335
336 return (ne->ei == ei);
337 }