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"
56 #include "eigrpd/eigrp_errors.h"
58 struct eigrp_neighbor
*eigrp_nbr_new(struct eigrp_interface
*ei
)
60 struct eigrp_neighbor
*nbr
;
62 /* Allcate new neighbor. */
63 nbr
= XCALLOC(MTYPE_EIGRP_NEIGHBOR
, sizeof(struct eigrp_neighbor
));
65 /* Relate neighbor to the interface. */
68 /* Set default values. */
69 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
75 *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
79 * Create a new neighbor structure and initalize it.
81 static struct eigrp_neighbor
*eigrp_nbr_add(struct eigrp_interface
*ei
,
82 struct eigrp_header
*eigrph
,
85 struct eigrp_neighbor
*nbr
;
87 nbr
= eigrp_nbr_new(ei
);
88 nbr
->src
= iph
->ip_src
;
93 struct eigrp_neighbor
*eigrp_nbr_get(struct eigrp_interface
*ei
,
94 struct eigrp_header
*eigrph
,
97 struct eigrp_neighbor
*nbr
;
98 struct listnode
*node
, *nnode
;
100 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
101 if (iph
->ip_src
.s_addr
== nbr
->src
.s_addr
) {
106 nbr
= eigrp_nbr_add(ei
, eigrph
, iph
);
107 listnode_add(ei
->nbrs
, nbr
);
113 * @fn eigrp_nbr_lookup_by_addr
115 * @param[in] ei EIGRP interface
116 * @param[in] nbr_addr Address of neighbor
121 * Function is used for neighbor lookup by address
122 * in specified interface.
124 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr(struct eigrp_interface
*ei
,
125 struct in_addr
*addr
)
127 struct eigrp_neighbor
*nbr
;
128 struct listnode
*node
, *nnode
;
130 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
131 if (addr
->s_addr
== nbr
->src
.s_addr
) {
140 * @fn eigrp_nbr_lookup_by_addr_process
142 * @param[in] eigrp EIGRP process
143 * @param[in] nbr_addr Address of neighbor
148 * Function is used for neighbor lookup by address
149 * in whole EIGRP process.
151 struct eigrp_neighbor
*eigrp_nbr_lookup_by_addr_process(struct eigrp
*eigrp
,
152 struct in_addr nbr_addr
)
154 struct eigrp_interface
*ei
;
155 struct listnode
*node
, *node2
, *nnode2
;
156 struct eigrp_neighbor
*nbr
;
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
) {
173 /* Delete specified EIGRP neighbor from interface. */
174 void eigrp_nbr_delete(struct eigrp_neighbor
*nbr
)
176 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
178 eigrp_topology_neighbor_down(nbr
->ei
->eigrp
, nbr
);
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
);
187 listnode_delete(nbr
->ei
->nbrs
, nbr
);
188 XFREE(MTYPE_EIGRP_NEIGHBOR
, nbr
);
191 int holddown_timer_expired(struct thread
*thread
)
193 struct eigrp_neighbor
*nbr
= THREAD_ARG(thread
);
194 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
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
);
204 uint8_t eigrp_nbr_state_get(struct eigrp_neighbor
*nbr
)
209 void eigrp_nbr_state_set(struct eigrp_neighbor
*nbr
, uint8_t state
)
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;
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
;
228 nbr
->v_holddown
= EIGRP_HOLD_INTERVAL_DEFAULT
;
229 THREAD_OFF(nbr
->t_holddown
);
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
);
237 /* in with the new */
238 nbr
->retrans_queue
= eigrp_fifo_new();
239 nbr
->multicast_queue
= eigrp_fifo_new();
241 nbr
->crypt_seqnum
= 0;
245 const char *eigrp_nbr_state_str(struct eigrp_neighbor
*nbr
)
248 switch (nbr
->state
) {
249 case EIGRP_NEIGHBOR_DOWN
:
252 case EIGRP_NEIGHBOR_PENDING
:
253 state
= "Waiting for Init";
255 case EIGRP_NEIGHBOR_UP
:
266 void eigrp_nbr_state_update(struct eigrp_neighbor
*nbr
)
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);
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
);
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
);
294 int eigrp_nbr_count_get(struct eigrp
*eigrp
)
296 struct eigrp_interface
*iface
;
297 struct listnode
*node
, *node2
, *nnode2
;
298 struct eigrp_neighbor
*nbr
;
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
) {
313 * @fn eigrp_nbr_hard_restart
315 * @param[in] nbr Neighbor who would receive hard restart
316 * @param[in] vty Virtual terminal for log output
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
324 void eigrp_nbr_hard_restart(struct eigrp_neighbor
*nbr
, struct vty
*vty
)
326 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
328 zlog_debug("Neighbor %pI4 (%s) is down: manually cleared", &nbr
->src
,
329 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
331 vty_time_print(vty
, 0);
332 vty_out(vty
, "Neighbor %pI4 (%s) is down: manually cleared\n",
334 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
337 /* send Hello with Peer Termination TLV */
338 eigrp_hello_send(nbr
->ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR
,
340 /* set neighbor to DOWN */
341 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
342 /* delete neighbor */
343 eigrp_nbr_delete(nbr
);
346 int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor
*ne
,
347 struct eigrp_interface
*ei
)
349 if (ne
->distance
== EIGRP_MAX_METRIC
)
352 return (ne
->ei
== ei
);