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