]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_neighbor.c
eigrp: Initial Commit
[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
28 * along with GNU Zebra; see the file COPYING. If not, write to the Free
29 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 * 02111-1307, USA.
31 */
32
33 #include <zebra.h>
34
35 #include "linklist.h"
36 #include "prefix.h"
37 #include "memory.h"
38 #include "command.h"
39 #include "thread.h"
40 #include "stream.h"
41 #include "table.h"
42 #include "log.h"
43 #include "keychain.h"
44 #include "vty.h"
45
46 #include "eigrpd/eigrp_structs.h"
47 #include "eigrpd/eigrpd.h"
48 #include "eigrpd/eigrp_interface.h"
49 #include "eigrpd/eigrp_neighbor.h"
50 #include "eigrpd/eigrp_dump.h"
51 #include "eigrpd/eigrp_packet.h"
52 #include "eigrpd/eigrp_zebra.h"
53 #include "eigrpd/eigrp_vty.h"
54 #include "eigrpd/eigrp_network.h"
55 #include "eigrpd/eigrp_topology.h"
56 #include "eigrpd/eigrp_memory.h"
57
58 struct eigrp_neighbor *
59 eigrp_nbr_new (struct eigrp_interface *ei)
60 {
61 struct eigrp_neighbor *nbr;
62
63 /* Allcate new neighbor. */
64 nbr = XCALLOC (MTYPE_EIGRP_NEIGHBOR, sizeof (struct eigrp_neighbor));
65
66 /* Relate neighbor to the interface. */
67 nbr->ei = ei;
68
69 /* Set default values. */
70
71 eigrp_nbr_state_set (nbr, EIGRP_NEIGHBOR_DOWN);
72
73 return nbr;
74 }
75
76 /**
77 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
78 * proto_item *ti)
79 *
80 * @par
81 * Create a new neighbor structure and initalize it.
82 */
83 static struct eigrp_neighbor *
84 eigrp_nbr_add (struct eigrp_interface *ei, struct eigrp_header *eigrph,
85 struct ip *iph)
86 {
87 struct eigrp_neighbor *nbr;
88
89 nbr = eigrp_nbr_new (ei);
90 nbr->src = iph->ip_src;
91
92 // if (IS_DEBUG_EIGRP_EVENT)
93 // zlog_debug("NSM[%s:%s]: start", IF_NAME (nbr->oi),
94 // inet_ntoa (nbr->router_id));
95
96 return nbr;
97 }
98
99 struct eigrp_neighbor *
100 eigrp_nbr_get (struct eigrp_interface *ei, struct eigrp_header *eigrph,
101 struct ip *iph)
102 {
103 struct eigrp_neighbor *nbr;
104 struct listnode *node, *nnode;
105
106 for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
107 {
108 if (iph->ip_src.s_addr == nbr->src.s_addr)
109 {
110 return nbr;
111 }
112 }
113
114 nbr = eigrp_nbr_add (ei, eigrph, iph);
115 listnode_add (ei->nbrs, nbr);
116
117 return nbr;
118 }
119
120 /**
121 * @fn eigrp_nbr_lookup_by_addr
122 *
123 * @param[in] ei EIGRP interface
124 * @param[in] nbr_addr Address of neighbor
125 *
126 * @return void
127 *
128 * @par
129 * Function is used for neighbor lookup by address
130 * in specified interface.
131 */
132 struct eigrp_neighbor *
133 eigrp_nbr_lookup_by_addr (struct eigrp_interface *ei, struct in_addr *addr)
134 {
135 struct eigrp_neighbor *nbr;
136 struct listnode *node, *nnode;
137
138 for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
139 {
140 if (addr->s_addr == nbr->src.s_addr)
141 {
142 return nbr;
143 }
144 }
145
146 return NULL;
147 }
148
149 /**
150 * @fn eigrp_nbr_lookup_by_addr_process
151 *
152 * @param[in] eigrp EIGRP process
153 * @param[in] nbr_addr Address of neighbor
154 *
155 * @return void
156 *
157 * @par
158 * Function is used for neighbor lookup by address
159 * in whole EIGRP process.
160 */
161 struct eigrp_neighbor *
162 eigrp_nbr_lookup_by_addr_process (struct eigrp *eigrp, struct in_addr nbr_addr)
163 {
164 struct eigrp_interface *ei;
165 struct listnode *node, *node2, *nnode2;
166 struct eigrp_neighbor *nbr;
167
168 /* iterate over all eigrp interfaces */
169 for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
170 {
171 /* iterate over all neighbors on eigrp interface */
172 for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
173 {
174 /* compare if neighbor address is same as arg address */
175 if (nbr->src.s_addr == nbr_addr.s_addr)
176 {
177 return nbr;
178 }
179 }
180 }
181
182 return NULL;
183 }
184
185
186 /* Delete specified EIGRP neighbor from interface. */
187 void
188 eigrp_nbr_delete (struct eigrp_neighbor *nbr)
189 {
190
191 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
192 eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
193
194 /* Cancel all events. *//* Thread lookup cost would be negligible. */
195 thread_cancel_event (master, nbr);
196 eigrp_fifo_free (nbr->multicast_queue);
197 eigrp_fifo_free (nbr->retrans_queue);
198 THREAD_OFF (nbr->t_holddown);
199
200 listnode_delete (nbr->ei->nbrs,nbr);
201 XFREE (MTYPE_EIGRP_NEIGHBOR, nbr);
202 }
203
204 int
205 holddown_timer_expired (struct thread *thread)
206 {
207 struct eigrp_neighbor *nbr;
208
209 nbr = THREAD_ARG (thread);
210
211 zlog_info ("Neighbor %s (%s) is down: holding time expired",
212 inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
213 nbr->state = EIGRP_NEIGHBOR_DOWN;
214 eigrp_nbr_delete (nbr);
215
216 return 0;
217 }
218
219 u_char
220 eigrp_nbr_state_get (struct eigrp_neighbor *nbr)
221 {
222 return(nbr->state);
223 }
224
225 void
226 eigrp_nbr_state_set (struct eigrp_neighbor *nbr, u_char state)
227 {
228
229 nbr->state = state;
230
231 if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN)
232 {
233 // reset all the seq/ack counters
234 nbr->recv_sequence_number = 0;
235 nbr->init_sequence_number = 0;
236 nbr->retrans_counter = 0;
237
238 // Kvalues
239 nbr->K1 = EIGRP_K1_DEFAULT;
240 nbr->K2 = EIGRP_K2_DEFAULT;
241 nbr->K3 = EIGRP_K3_DEFAULT;
242 nbr->K4 = EIGRP_K4_DEFAULT;
243 nbr->K5 = EIGRP_K5_DEFAULT;
244 nbr->K6 = EIGRP_K6_DEFAULT;
245
246 // hold time..
247 nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT;
248 THREAD_OFF(nbr->t_holddown);
249
250 /* out with the old */
251 if (nbr->multicast_queue)
252 eigrp_fifo_free (nbr->multicast_queue);
253 if (nbr->retrans_queue)
254 eigrp_fifo_free (nbr->retrans_queue);
255
256 /* in with the new */
257 nbr->retrans_queue = eigrp_fifo_new ();
258 nbr->multicast_queue = eigrp_fifo_new ();
259
260 nbr->crypt_seqnum = 0;
261 }
262 }
263
264 const char *
265 eigrp_nbr_state_str (struct eigrp_neighbor *nbr)
266 {
267 const char *state;
268 switch (nbr->state)
269 {
270 case EIGRP_NEIGHBOR_DOWN:
271 state = "Down";
272 break;
273 case EIGRP_NEIGHBOR_PENDING:
274 state = "Waiting for Init";
275 break;
276 case EIGRP_NEIGHBOR_UP:
277 state = "Up";
278 break;
279 default:
280 state = "Unknown";
281 break;
282 }
283
284 return(state);
285 }
286
287 void
288 eigrp_nbr_state_update (struct eigrp_neighbor *nbr)
289 {
290 switch (nbr->state)
291 {
292 case EIGRP_NEIGHBOR_DOWN:
293 {
294 /*Start Hold Down Timer for neighbor*/
295 // THREAD_OFF(nbr->t_holddown);
296 // THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired,
297 // nbr, nbr->v_holddown);
298 break;
299 }
300 case EIGRP_NEIGHBOR_PENDING:
301 {
302 /*Reset Hold Down Timer for neighbor*/
303 THREAD_OFF(nbr->t_holddown);
304 THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
305 nbr->v_holddown);
306 break;
307 }
308 case EIGRP_NEIGHBOR_UP:
309 {
310 /*Reset Hold Down Timer for neighbor*/
311 THREAD_OFF(nbr->t_holddown);
312 THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
313 nbr->v_holddown);
314 break;
315 }
316 }
317 }
318
319 int eigrp_nbr_count_get(void){
320
321 struct eigrp_interface *iface;
322 struct listnode *node, *node2, *nnode2;
323 struct eigrp_neighbor *nbr;
324 struct eigrp *eigrp = eigrp_lookup();
325 u_int32_t counter;
326
327 if (eigrp == NULL)
328 {
329 zlog_debug("EIGRP Routing Process not enabled");
330 return 0;
331 }
332
333 counter=0;
334 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
335 {
336 for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr))
337 {
338 if (nbr->state == EIGRP_NEIGHBOR_UP){
339 counter++;
340 }
341 }
342 }
343 return counter;
344 }
345
346 /**
347 * @fn eigrp_nbr_hard_restart
348 *
349 * @param[in] nbr Neighbor who would receive hard restart
350 * @param[in] vty Virtual terminal for log output
351 * @return void
352 *
353 * @par
354 * Function used for executing hard restart for neighbor:
355 * Send Hello packet with Peer Termination TLV with
356 * neighbor's address, set it's state to DOWN and delete the neighbor
357 */
358 void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
359 {
360 if(nbr == NULL)
361 {
362 zlog_err("Nbr Hard restart: Neighbor not specified.");
363 return;
364 }
365
366 zlog_debug ("Neighbor %s (%s) is down: manually cleared",
367 inet_ntoa (nbr->src),
368 ifindex2ifname (nbr->ei->ifp->ifindex));
369 if(vty != NULL)
370 {
371 vty_time_print (vty, 0);
372 vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s",
373 inet_ntoa (nbr->src),
374 ifindex2ifname (nbr->ei->ifp->ifindex),
375 VTY_NEWLINE);
376 }
377
378 /* send Hello with Peer Termination TLV */
379 eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, &(nbr->src));
380 /* set neighbor to DOWN */
381 nbr->state = EIGRP_NEIGHBOR_DOWN;
382 /* delete neighbor */
383 eigrp_nbr_delete (nbr);
384 }