2 * EIGRP Neighbor Handling.
3 * Copyright (C) 2013-2016
15 * This file is part of GNU Zebra.
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
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.
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
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"
57 struct eigrp_neighbor
*eigrp_nbr_new(struct eigrp_interface
*ei
)
59 struct eigrp_neighbor
*nbr
;
61 /* Allcate new neighbor. */
62 nbr
= XCALLOC(MTYPE_EIGRP_NEIGHBOR
, sizeof(struct eigrp_neighbor
));
64 /* Relate neighbor to the interface. */
67 /* Set default values. */
68 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
74 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
78 * Create a new neighbor structure and initalize it.
80 static struct eigrp_neighbor
*eigrp_nbr_add(struct eigrp_interface
*ei
,
81 struct eigrp_header
*eigrph
,
84 struct eigrp_neighbor
*nbr
;
86 nbr
= eigrp_nbr_new(ei
);
87 nbr
->src
= iph
->ip_src
;
89 // if (IS_DEBUG_EIGRP_EVENT)
90 // zlog_debug("NSM[%s:%s]: start", IF_NAME (nbr->oi),
91 // inet_ntoa (nbr->router_id));
96 struct eigrp_neighbor
*eigrp_nbr_get(struct eigrp_interface
*ei
,
97 struct eigrp_header
*eigrph
,
100 struct eigrp_neighbor
*nbr
;
101 struct listnode
*node
, *nnode
;
103 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
104 if (iph
->ip_src
.s_addr
== nbr
->src
.s_addr
) {
109 nbr
= eigrp_nbr_add(ei
, eigrph
, iph
);
110 listnode_add(ei
->nbrs
, nbr
);
116 * @fn eigrp_nbr_lookup_by_addr
118 * @param[in] ei EIGRP interface
119 * @param[in] nbr_addr Address of neighbor
124 * Function is used for neighbor lookup by address
125 * in specified interface.
127 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr(struct eigrp_interface
*ei
,
128 struct in_addr
*addr
)
130 struct eigrp_neighbor
*nbr
;
131 struct listnode
*node
, *nnode
;
133 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
134 if (addr
->s_addr
== nbr
->src
.s_addr
) {
143 * @fn eigrp_nbr_lookup_by_addr_process
145 * @param[in] eigrp EIGRP process
146 * @param[in] nbr_addr Address of neighbor
151 * Function is used for neighbor lookup by address
152 * in whole EIGRP process.
154 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr_process(struct eigrp
*eigrp
,
155 struct in_addr nbr_addr
)
157 struct eigrp_interface
*ei
;
158 struct listnode
*node
, *node2
, *nnode2
;
159 struct eigrp_neighbor
*nbr
;
161 /* iterate over all eigrp interfaces */
162 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
163 /* iterate over all neighbors on eigrp interface */
164 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node2
, nnode2
, nbr
)) {
165 /* compare if neighbor address is same as arg address */
166 if (nbr
->src
.s_addr
== nbr_addr
.s_addr
) {
176 /* Delete specified EIGRP neighbor from interface. */
177 void eigrp_nbr_delete(struct eigrp_neighbor
*nbr
)
179 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
181 eigrp_topology_neighbor_down(nbr
->ei
->eigrp
, nbr
);
183 /* Cancel all events. */ /* Thread lookup cost would be negligible. */
184 thread_cancel_event(master
, nbr
);
185 eigrp_fifo_free(nbr
->multicast_queue
);
186 eigrp_fifo_free(nbr
->retrans_queue
);
187 THREAD_OFF(nbr
->t_holddown
);
190 listnode_delete(nbr
->ei
->nbrs
, nbr
);
191 XFREE(MTYPE_EIGRP_NEIGHBOR
, nbr
);
194 int holddown_timer_expired(struct thread
*thread
)
196 struct eigrp_neighbor
*nbr
;
198 nbr
= THREAD_ARG(thread
);
200 zlog_info("Neighbor %s (%s) is down: holding time expired",
202 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, VRF_DEFAULT
));
203 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
204 eigrp_nbr_delete(nbr
);
209 uint8_t eigrp_nbr_state_get(struct eigrp_neighbor
*nbr
)
214 void eigrp_nbr_state_set(struct eigrp_neighbor
*nbr
, uint8_t state
)
218 if (eigrp_nbr_state_get(nbr
) == EIGRP_NEIGHBOR_DOWN
) {
219 // reset all the seq/ack counters
220 nbr
->recv_sequence_number
= 0;
221 nbr
->init_sequence_number
= 0;
222 nbr
->retrans_counter
= 0;
225 nbr
->K1
= EIGRP_K1_DEFAULT
;
226 nbr
->K2
= EIGRP_K2_DEFAULT
;
227 nbr
->K3
= EIGRP_K3_DEFAULT
;
228 nbr
->K4
= EIGRP_K4_DEFAULT
;
229 nbr
->K5
= EIGRP_K5_DEFAULT
;
230 nbr
->K6
= EIGRP_K6_DEFAULT
;
233 nbr
->v_holddown
= EIGRP_HOLD_INTERVAL_DEFAULT
;
234 THREAD_OFF(nbr
->t_holddown
);
236 /* out with the old */
237 if (nbr
->multicast_queue
)
238 eigrp_fifo_free(nbr
->multicast_queue
);
239 if (nbr
->retrans_queue
)
240 eigrp_fifo_free(nbr
->retrans_queue
);
242 /* in with the new */
243 nbr
->retrans_queue
= eigrp_fifo_new();
244 nbr
->multicast_queue
= eigrp_fifo_new();
246 nbr
->crypt_seqnum
= 0;
250 const char *eigrp_nbr_state_str(struct eigrp_neighbor
*nbr
)
253 switch (nbr
->state
) {
254 case EIGRP_NEIGHBOR_DOWN
:
257 case EIGRP_NEIGHBOR_PENDING
:
258 state
= "Waiting for Init";
260 case EIGRP_NEIGHBOR_UP
:
271 void eigrp_nbr_state_update(struct eigrp_neighbor
*nbr
)
273 switch (nbr
->state
) {
274 case EIGRP_NEIGHBOR_DOWN
: {
275 /*Start Hold Down Timer for neighbor*/
276 // THREAD_OFF(nbr->t_holddown);
277 // THREAD_TIMER_ON(master, nbr->t_holddown,
278 // holddown_timer_expired,
279 // nbr, nbr->v_holddown);
282 case EIGRP_NEIGHBOR_PENDING
: {
283 /*Reset Hold Down Timer for neighbor*/
284 THREAD_OFF(nbr
->t_holddown
);
285 thread_add_timer(master
, holddown_timer_expired
, nbr
,
286 nbr
->v_holddown
, &nbr
->t_holddown
);
289 case EIGRP_NEIGHBOR_UP
: {
290 /*Reset Hold Down Timer for neighbor*/
291 THREAD_OFF(nbr
->t_holddown
);
292 thread_add_timer(master
, holddown_timer_expired
, nbr
,
293 nbr
->v_holddown
, &nbr
->t_holddown
);
299 int eigrp_nbr_count_get(void)
301 struct eigrp_interface
*iface
;
302 struct listnode
*node
, *node2
, *nnode2
;
303 struct eigrp_neighbor
*nbr
;
304 struct eigrp
*eigrp
= eigrp_lookup();
308 zlog_debug("EIGRP Routing Process not enabled");
313 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, iface
)) {
314 for (ALL_LIST_ELEMENTS(iface
->nbrs
, node2
, nnode2
, nbr
)) {
315 if (nbr
->state
== EIGRP_NEIGHBOR_UP
) {
324 * @fn eigrp_nbr_hard_restart
326 * @param[in] nbr Neighbor who would receive hard restart
327 * @param[in] vty Virtual terminal for log output
331 * Function used for executing hard restart for neighbor:
332 * Send Hello packet with Peer Termination TLV with
333 * neighbor's address, set it's state to DOWN and delete the neighbor
335 void eigrp_nbr_hard_restart(struct eigrp_neighbor
*nbr
, struct vty
*vty
)
338 zlog_err("Nbr Hard restart: Neighbor not specified.");
342 zlog_debug("Neighbor %s (%s) is down: manually cleared",
344 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, VRF_DEFAULT
));
346 vty_time_print(vty
, 0);
347 vty_out(vty
, "Neighbor %s (%s) is down: manually cleared\n",
349 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, VRF_DEFAULT
));
352 /* send Hello with Peer Termination TLV */
353 eigrp_hello_send(nbr
->ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR
,
355 /* set neighbor to DOWN */
356 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
357 /* delete neighbor */
358 eigrp_nbr_delete(nbr
);
361 int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry
*ne
,
362 struct eigrp_interface
*ei
)
364 if (ne
->distance
== EIGRP_MAX_METRIC
)
367 return (ne
->ei
== ei
);