1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * EIGRP Neighbor Handling.
4 * Copyright (C) 2013-2016
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"
42 DEFINE_MTYPE_STATIC(EIGRPD
, EIGRP_NEIGHBOR
, "EIGRP neighbor");
44 struct eigrp_neighbor
*eigrp_nbr_new(struct eigrp_interface
*ei
)
46 struct eigrp_neighbor
*nbr
;
48 /* Allcate new neighbor. */
49 nbr
= XCALLOC(MTYPE_EIGRP_NEIGHBOR
, sizeof(struct eigrp_neighbor
));
51 /* Relate neighbor to the interface. */
54 /* Set default values. */
55 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
61 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
65 * Create a new neighbor structure and initalize it.
67 static struct eigrp_neighbor
*eigrp_nbr_add(struct eigrp_interface
*ei
,
68 struct eigrp_header
*eigrph
,
71 struct eigrp_neighbor
*nbr
;
73 nbr
= eigrp_nbr_new(ei
);
74 nbr
->src
= iph
->ip_src
;
79 struct eigrp_neighbor
*eigrp_nbr_get(struct eigrp_interface
*ei
,
80 struct eigrp_header
*eigrph
,
83 struct eigrp_neighbor
*nbr
;
84 struct listnode
*node
, *nnode
;
86 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
87 if (iph
->ip_src
.s_addr
== nbr
->src
.s_addr
) {
92 nbr
= eigrp_nbr_add(ei
, eigrph
, iph
);
93 listnode_add(ei
->nbrs
, nbr
);
99 * @fn eigrp_nbr_lookup_by_addr
101 * @param[in] ei EIGRP interface
102 * @param[in] nbr_addr Address of neighbor
107 * Function is used for neighbor lookup by address
108 * in specified interface.
110 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr(struct eigrp_interface
*ei
,
111 struct in_addr
*addr
)
113 struct eigrp_neighbor
*nbr
;
114 struct listnode
*node
, *nnode
;
116 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
117 if (addr
->s_addr
== nbr
->src
.s_addr
) {
126 * @fn eigrp_nbr_lookup_by_addr_process
128 * @param[in] eigrp EIGRP process
129 * @param[in] nbr_addr Address of neighbor
134 * Function is used for neighbor lookup by address
135 * in whole EIGRP process.
137 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr_process(struct eigrp
*eigrp
,
138 struct in_addr nbr_addr
)
140 struct eigrp_interface
*ei
;
141 struct listnode
*node
, *node2
, *nnode2
;
142 struct eigrp_neighbor
*nbr
;
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
) {
159 /* Delete specified EIGRP neighbor from interface. */
160 void eigrp_nbr_delete(struct eigrp_neighbor
*nbr
)
162 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
164 eigrp_topology_neighbor_down(nbr
->ei
->eigrp
, nbr
);
166 /* Cancel all events. */ /* Thread lookup cost would be negligible. */
167 event_cancel_event(master
, nbr
);
168 eigrp_fifo_free(nbr
->multicast_queue
);
169 eigrp_fifo_free(nbr
->retrans_queue
);
170 EVENT_OFF(nbr
->t_holddown
);
173 listnode_delete(nbr
->ei
->nbrs
, nbr
);
174 XFREE(MTYPE_EIGRP_NEIGHBOR
, nbr
);
177 void holddown_timer_expired(struct event
*thread
)
179 struct eigrp_neighbor
*nbr
= EVENT_ARG(thread
);
180 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
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
);
188 uint8_t eigrp_nbr_state_get(struct eigrp_neighbor
*nbr
)
193 void eigrp_nbr_state_set(struct eigrp_neighbor
*nbr
, uint8_t state
)
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;
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
;
212 nbr
->v_holddown
= EIGRP_HOLD_INTERVAL_DEFAULT
;
213 EVENT_OFF(nbr
->t_holddown
);
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
);
221 /* in with the new */
222 nbr
->retrans_queue
= eigrp_fifo_new();
223 nbr
->multicast_queue
= eigrp_fifo_new();
225 nbr
->crypt_seqnum
= 0;
229 const char *eigrp_nbr_state_str(struct eigrp_neighbor
*nbr
)
232 switch (nbr
->state
) {
233 case EIGRP_NEIGHBOR_DOWN
:
236 case EIGRP_NEIGHBOR_PENDING
:
237 state
= "Waiting for Init";
239 case EIGRP_NEIGHBOR_UP
:
250 void eigrp_nbr_state_update(struct eigrp_neighbor
*nbr
)
252 switch (nbr
->state
) {
253 case EIGRP_NEIGHBOR_DOWN
: {
254 /*Start Hold Down Timer for neighbor*/
255 // EVENT_OFF(nbr->t_holddown);
256 // EVENT_TIMER_ON(master, nbr->t_holddown,
257 // holddown_timer_expired,
258 // nbr, nbr->v_holddown);
261 case EIGRP_NEIGHBOR_PENDING
: {
262 /*Reset Hold Down Timer for neighbor*/
263 EVENT_OFF(nbr
->t_holddown
);
264 event_add_timer(master
, holddown_timer_expired
, nbr
,
265 nbr
->v_holddown
, &nbr
->t_holddown
);
268 case EIGRP_NEIGHBOR_UP
: {
269 /*Reset Hold Down Timer for neighbor*/
270 EVENT_OFF(nbr
->t_holddown
);
271 event_add_timer(master
, holddown_timer_expired
, nbr
,
272 nbr
->v_holddown
, &nbr
->t_holddown
);
278 int eigrp_nbr_count_get(struct eigrp
*eigrp
)
280 struct eigrp_interface
*iface
;
281 struct listnode
*node
, *node2
, *nnode2
;
282 struct eigrp_neighbor
*nbr
;
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
) {
297 * @fn eigrp_nbr_hard_restart
299 * @param[in] nbr Neighbor who would receive hard restart
300 * @param[in] vty Virtual terminal for log output
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
308 void eigrp_nbr_hard_restart(struct eigrp_neighbor
*nbr
, struct vty
*vty
)
310 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
312 zlog_debug("Neighbor %pI4 (%s) is down: manually cleared", &nbr
->src
,
313 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
315 vty_time_print(vty
, 0);
316 vty_out(vty
, "Neighbor %pI4 (%s) is down: manually cleared\n",
318 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
321 /* send Hello with Peer Termination TLV */
322 eigrp_hello_send(nbr
->ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR
,
324 /* set neighbor to DOWN */
325 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
326 /* delete neighbor */
327 eigrp_nbr_delete(nbr
);
330 int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor
*ne
,
331 struct eigrp_interface
*ei
)
333 if (ne
->distance
== EIGRP_MAX_METRIC
)
336 return (ne
->ei
== ei
);