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_errors.h"
57 DEFINE_MTYPE_STATIC(EIGRPD
, EIGRP_NEIGHBOR
, "EIGRP neighbor");
59 struct eigrp_neighbor
*eigrp_nbr_new(struct eigrp_interface
*ei
)
61 struct eigrp_neighbor
*nbr
;
63 /* Allcate new neighbor. */
64 nbr
= XCALLOC(MTYPE_EIGRP_NEIGHBOR
, sizeof(struct eigrp_neighbor
));
66 /* Relate neighbor to the interface. */
69 /* Set default values. */
70 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
76 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
80 * Create a new neighbor structure and initalize it.
82 static struct eigrp_neighbor
*eigrp_nbr_add(struct eigrp_interface
*ei
,
83 struct eigrp_header
*eigrph
,
86 struct eigrp_neighbor
*nbr
;
88 nbr
= eigrp_nbr_new(ei
);
89 nbr
->src
= iph
->ip_src
;
94 struct eigrp_neighbor
*eigrp_nbr_get(struct eigrp_interface
*ei
,
95 struct eigrp_header
*eigrph
,
98 struct eigrp_neighbor
*nbr
;
99 struct listnode
*node
, *nnode
;
101 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
102 if (iph
->ip_src
.s_addr
== nbr
->src
.s_addr
) {
107 nbr
= eigrp_nbr_add(ei
, eigrph
, iph
);
108 listnode_add(ei
->nbrs
, nbr
);
114 * @fn eigrp_nbr_lookup_by_addr
116 * @param[in] ei EIGRP interface
117 * @param[in] nbr_addr Address of neighbor
122 * Function is used for neighbor lookup by address
123 * in specified interface.
125 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr(struct eigrp_interface
*ei
,
126 struct in_addr
*addr
)
128 struct eigrp_neighbor
*nbr
;
129 struct listnode
*node
, *nnode
;
131 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
132 if (addr
->s_addr
== nbr
->src
.s_addr
) {
141 * @fn eigrp_nbr_lookup_by_addr_process
143 * @param[in] eigrp EIGRP process
144 * @param[in] nbr_addr Address of neighbor
149 * Function is used for neighbor lookup by address
150 * in whole EIGRP process.
152 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr_process(struct eigrp
*eigrp
,
153 struct in_addr nbr_addr
)
155 struct eigrp_interface
*ei
;
156 struct listnode
*node
, *node2
, *nnode2
;
157 struct eigrp_neighbor
*nbr
;
159 /* iterate over all eigrp interfaces */
160 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
161 /* iterate over all neighbors on eigrp interface */
162 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node2
, nnode2
, nbr
)) {
163 /* compare if neighbor address is same as arg address */
164 if (nbr
->src
.s_addr
== nbr_addr
.s_addr
) {
174 /* Delete specified EIGRP neighbor from interface. */
175 void eigrp_nbr_delete(struct eigrp_neighbor
*nbr
)
177 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
179 eigrp_topology_neighbor_down(nbr
->ei
->eigrp
, nbr
);
181 /* Cancel all events. */ /* Thread lookup cost would be negligible. */
182 thread_cancel_event(master
, nbr
);
183 eigrp_fifo_free(nbr
->multicast_queue
);
184 eigrp_fifo_free(nbr
->retrans_queue
);
185 THREAD_OFF(nbr
->t_holddown
);
188 listnode_delete(nbr
->ei
->nbrs
, nbr
);
189 XFREE(MTYPE_EIGRP_NEIGHBOR
, nbr
);
192 void holddown_timer_expired(struct thread
*thread
)
194 struct eigrp_neighbor
*nbr
= THREAD_ARG(thread
);
195 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
197 zlog_info("Neighbor %pI4 (%s) is down: holding time expired", &nbr
->src
,
198 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
199 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
200 eigrp_nbr_delete(nbr
);
203 uint8_t eigrp_nbr_state_get(struct eigrp_neighbor
*nbr
)
208 void eigrp_nbr_state_set(struct eigrp_neighbor
*nbr
, uint8_t state
)
212 if (eigrp_nbr_state_get(nbr
) == EIGRP_NEIGHBOR_DOWN
) {
213 // reset all the seq/ack counters
214 nbr
->recv_sequence_number
= 0;
215 nbr
->init_sequence_number
= 0;
216 nbr
->retrans_counter
= 0;
219 nbr
->K1
= EIGRP_K1_DEFAULT
;
220 nbr
->K2
= EIGRP_K2_DEFAULT
;
221 nbr
->K3
= EIGRP_K3_DEFAULT
;
222 nbr
->K4
= EIGRP_K4_DEFAULT
;
223 nbr
->K5
= EIGRP_K5_DEFAULT
;
224 nbr
->K6
= EIGRP_K6_DEFAULT
;
227 nbr
->v_holddown
= EIGRP_HOLD_INTERVAL_DEFAULT
;
228 THREAD_OFF(nbr
->t_holddown
);
230 /* out with the old */
231 if (nbr
->multicast_queue
)
232 eigrp_fifo_free(nbr
->multicast_queue
);
233 if (nbr
->retrans_queue
)
234 eigrp_fifo_free(nbr
->retrans_queue
);
236 /* in with the new */
237 nbr
->retrans_queue
= eigrp_fifo_new();
238 nbr
->multicast_queue
= eigrp_fifo_new();
240 nbr
->crypt_seqnum
= 0;
244 const char *eigrp_nbr_state_str(struct eigrp_neighbor
*nbr
)
247 switch (nbr
->state
) {
248 case EIGRP_NEIGHBOR_DOWN
:
251 case EIGRP_NEIGHBOR_PENDING
:
252 state
= "Waiting for Init";
254 case EIGRP_NEIGHBOR_UP
:
265 void eigrp_nbr_state_update(struct eigrp_neighbor
*nbr
)
267 switch (nbr
->state
) {
268 case EIGRP_NEIGHBOR_DOWN
: {
269 /*Start Hold Down Timer for neighbor*/
270 // THREAD_OFF(nbr->t_holddown);
271 // THREAD_TIMER_ON(master, nbr->t_holddown,
272 // holddown_timer_expired,
273 // nbr, nbr->v_holddown);
276 case EIGRP_NEIGHBOR_PENDING
: {
277 /*Reset Hold Down Timer for neighbor*/
278 THREAD_OFF(nbr
->t_holddown
);
279 thread_add_timer(master
, holddown_timer_expired
, nbr
,
280 nbr
->v_holddown
, &nbr
->t_holddown
);
283 case EIGRP_NEIGHBOR_UP
: {
284 /*Reset Hold Down Timer for neighbor*/
285 THREAD_OFF(nbr
->t_holddown
);
286 thread_add_timer(master
, holddown_timer_expired
, nbr
,
287 nbr
->v_holddown
, &nbr
->t_holddown
);
293 int eigrp_nbr_count_get(struct eigrp
*eigrp
)
295 struct eigrp_interface
*iface
;
296 struct listnode
*node
, *node2
, *nnode2
;
297 struct eigrp_neighbor
*nbr
;
301 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, iface
)) {
302 for (ALL_LIST_ELEMENTS(iface
->nbrs
, node2
, nnode2
, nbr
)) {
303 if (nbr
->state
== EIGRP_NEIGHBOR_UP
) {
312 * @fn eigrp_nbr_hard_restart
314 * @param[in] nbr Neighbor who would receive hard restart
315 * @param[in] vty Virtual terminal for log output
319 * Function used for executing hard restart for neighbor:
320 * Send Hello packet with Peer Termination TLV with
321 * neighbor's address, set it's state to DOWN and delete the neighbor
323 void eigrp_nbr_hard_restart(struct eigrp_neighbor
*nbr
, struct vty
*vty
)
325 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
327 zlog_debug("Neighbor %pI4 (%s) is down: manually cleared", &nbr
->src
,
328 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
330 vty_time_print(vty
, 0);
331 vty_out(vty
, "Neighbor %pI4 (%s) is down: manually cleared\n",
333 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
336 /* send Hello with Peer Termination TLV */
337 eigrp_hello_send(nbr
->ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR
,
339 /* set neighbor to DOWN */
340 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
341 /* delete neighbor */
342 eigrp_nbr_delete(nbr
);
345 int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor
*ne
,
346 struct eigrp_interface
*ei
)
348 if (ne
->distance
== EIGRP_MAX_METRIC
)
351 return (ne
->ei
== ei
);