2 * EIGRP Interface Functions.
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
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_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_fsm.h"
58 static void eigrp_delete_from_if(struct interface
*, struct eigrp_interface
*);
60 static void eigrp_add_to_if(struct interface
*ifp
, struct eigrp_interface
*ei
)
62 struct route_node
*rn
;
66 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
68 rn
= route_node_get(IF_OIFS(ifp
), &p
);
69 /* rn->info should either be NULL or equal to this ei
70 * as route_node_get may return an existing node
72 assert(!rn
->info
|| rn
->info
== ei
);
76 struct eigrp_interface
*eigrp_if_new(struct eigrp
*eigrp
, struct interface
*ifp
,
79 struct eigrp_interface
*ei
;
82 if ((ei
= eigrp_if_table_lookup(ifp
, p
)) == NULL
) {
83 ei
= XCALLOC(MTYPE_EIGRP_IF
, sizeof(struct eigrp_interface
));
84 memset(ei
, 0, sizeof(struct eigrp_interface
));
88 /* Set zebra interface pointer. */
92 eigrp_add_to_if(ifp
, ei
);
93 listnode_add(eigrp
->eiflist
, ei
);
95 ei
->type
= EIGRP_IFTYPE_BROADCAST
;
97 /* Initialize neighbor list. */
98 ei
->nbrs
= list_new();
100 ei
->crypt_seqnum
= time(NULL
);
102 /* Initialize lists */
103 for (i
= 0; i
< EIGRP_FILTER_MAX
; i
++) {
105 ei
->prefix
[i
] = NULL
;
106 ei
->routemap
[i
] = NULL
;
112 /* lookup ei for specified prefix/ifp */
113 struct eigrp_interface
*eigrp_if_table_lookup(struct interface
*ifp
,
114 struct prefix
*prefix
)
117 struct route_node
*rn
;
118 struct eigrp_interface
*rninfo
= NULL
;
121 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
123 /* route_node_get implicitly locks */
124 if ((rn
= route_node_lookup(IF_OIFS(ifp
), &p
))) {
125 rninfo
= (struct eigrp_interface
*)rn
->info
;
126 route_unlock_node(rn
);
132 int eigrp_if_delete_hook(struct interface
*ifp
)
134 struct route_node
*rn
;
136 route_table_finish(IF_OIFS(ifp
));
138 for (rn
= route_top(IF_OIFS_PARAMS(ifp
)); rn
; rn
= route_next(rn
))
140 eigrp_del_if_params(rn
->info
);
141 route_table_finish(IF_OIFS_PARAMS(ifp
));
143 XFREE(MTYPE_EIGRP_IF_INFO
, ifp
->info
);
149 struct list
*eigrp_iflist
;
153 /* Initialize Zebra interface data structure. */
154 hook_register_prio(if_add
, 0, eigrp_if_new_hook
);
155 hook_register_prio(if_del
, 0, eigrp_if_delete_hook
);
158 int eigrp_if_new_hook(struct interface
*ifp
)
162 ifp
->info
= XCALLOC(MTYPE_EIGRP_IF_INFO
, sizeof(struct eigrp_if_info
));
164 IF_OIFS(ifp
) = route_table_init();
165 IF_OIFS_PARAMS(ifp
) = route_table_init();
167 IF_DEF_PARAMS(ifp
) = eigrp_new_if_params();
169 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), v_hello
);
170 IF_DEF_PARAMS(ifp
)->v_hello
= (u_int32_t
)EIGRP_HELLO_INTERVAL_DEFAULT
;
172 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), v_wait
);
173 IF_DEF_PARAMS(ifp
)->v_wait
= (u_int16_t
)EIGRP_HOLD_INTERVAL_DEFAULT
;
175 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), bandwidth
);
176 IF_DEF_PARAMS(ifp
)->bandwidth
= (u_int32_t
)EIGRP_BANDWIDTH_DEFAULT
;
178 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), delay
);
179 IF_DEF_PARAMS(ifp
)->delay
= (u_int32_t
)EIGRP_DELAY_DEFAULT
;
181 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), reliability
);
182 IF_DEF_PARAMS(ifp
)->reliability
= (u_char
)EIGRP_RELIABILITY_DEFAULT
;
184 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), load
);
185 IF_DEF_PARAMS(ifp
)->load
= (u_char
)EIGRP_LOAD_DEFAULT
;
187 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), auth_type
);
188 IF_DEF_PARAMS(ifp
)->auth_type
= EIGRP_AUTH_TYPE_NONE
;
190 SET_IF_PARAM(IF_DEF_PARAMS(ifp
), auth_keychain
);
191 IF_DEF_PARAMS(ifp
)->auth_keychain
= NULL
;
196 struct eigrp_if_params
*eigrp_new_if_params(void)
198 struct eigrp_if_params
*eip
;
200 eip
= XCALLOC(MTYPE_EIGRP_IF_PARAMS
, sizeof(struct eigrp_if_params
));
204 UNSET_IF_PARAM(eip
, passive_interface
);
205 UNSET_IF_PARAM(eip
, v_hello
);
206 UNSET_IF_PARAM(eip
, v_wait
);
207 UNSET_IF_PARAM(eip
, bandwidth
);
208 UNSET_IF_PARAM(eip
, delay
);
209 UNSET_IF_PARAM(eip
, reliability
);
210 UNSET_IF_PARAM(eip
, load
);
211 UNSET_IF_PARAM(eip
, auth_keychain
);
212 UNSET_IF_PARAM(eip
, auth_type
);
217 void eigrp_del_if_params(struct eigrp_if_params
*eip
)
219 if (eip
->auth_keychain
)
220 free(eip
->auth_keychain
);
222 XFREE(MTYPE_EIGRP_IF_PARAMS
, eip
);
225 struct eigrp_if_params
*eigrp_lookup_if_params(struct interface
*ifp
,
229 struct route_node
*rn
;
232 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
235 rn
= route_node_lookup(IF_OIFS_PARAMS(ifp
), &p
);
238 route_unlock_node(rn
);
245 int eigrp_if_up(struct eigrp_interface
*ei
)
247 struct eigrp_prefix_entry
*pe
;
248 struct eigrp_neighbor_entry
*ne
;
249 struct eigrp_metrics metric
;
250 struct eigrp_interface
*ei2
;
251 struct listnode
*node
, *nnode
;
252 struct eigrp
*eigrp
= eigrp_lookup();
258 eigrp_adjust_sndbuflen(eigrp
, ei
->ifp
->mtu
);
260 zlog_warn("%s: eigrp_lookup () returned NULL", __func__
);
261 eigrp_if_stream_set(ei
);
263 /* Set multicast memberships appropriately for new state. */
264 eigrp_if_set_multicast(ei
);
266 thread_add_event(master
, eigrp_hello_timer
, ei
, (1), NULL
);
270 eigrp_bandwidth_to_scaled(EIGRP_IF_PARAM(ei
, bandwidth
));
271 metric
.delay
= eigrp_delay_to_scaled(EIGRP_IF_PARAM(ei
, delay
));
272 metric
.load
= EIGRP_IF_PARAM(ei
, load
);
273 metric
.reliability
= EIGRP_IF_PARAM(ei
, reliability
);
274 metric
.mtu
[0] = 0xDC;
275 metric
.mtu
[1] = 0x05;
276 metric
.mtu
[2] = 0x00;
277 metric
.hop_count
= 0;
281 /*Add connected entry to topology table*/
283 ne
= eigrp_neighbor_entry_new();
285 ne
->reported_metric
= metric
;
286 ne
->total_metric
= metric
;
287 ne
->distance
= eigrp_calculate_metrics(eigrp
, metric
);
288 ne
->reported_distance
= 0;
289 ne
->adv_router
= eigrp
->neighbor_self
;
290 ne
->flags
= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
;
292 struct prefix dest_addr
;
294 dest_addr
.family
= AF_INET
;
295 dest_addr
.u
.prefix4
= ei
->connected
->address
->u
.prefix4
;
296 dest_addr
.prefixlen
= ei
->connected
->address
->prefixlen
;
297 apply_mask(&dest_addr
);
298 pe
= eigrp_topology_table_lookup_ipv4(eigrp
->topology_table
,
302 pe
= eigrp_prefix_entry_new();
303 pe
->serno
= eigrp
->serno
;
304 pe
->destination
= (struct prefix
*)prefix_ipv4_new();
305 prefix_copy(pe
->destination
, &dest_addr
);
307 pe
->nt
= EIGRP_TOPOLOGY_TYPE_CONNECTED
;
310 pe
->reported_metric
= metric
;
311 pe
->state
= EIGRP_FSM_STATE_PASSIVE
;
312 pe
->fdistance
= eigrp_calculate_metrics(eigrp
, metric
);
313 pe
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
314 eigrp_prefix_entry_add(eigrp
->topology_table
, pe
);
315 listnode_add(eigrp
->topology_changes_internalIPV4
, pe
);
317 eigrp_neighbor_entry_add(pe
, ne
);
319 for (ALL_LIST_ELEMENTS(eigrp
->eiflist
, node
, nnode
, ei2
)) {
320 eigrp_update_send(ei2
);
323 pe
->req_action
&= ~EIGRP_FSM_NEED_UPDATE
;
324 listnode_delete(eigrp
->topology_changes_internalIPV4
, pe
);
326 struct eigrp_fsm_action_message msg
;
329 eigrp_neighbor_entry_add(pe
, ne
);
331 msg
.packet_type
= EIGRP_OPC_UPDATE
;
333 msg
.data_type
= EIGRP_CONNECTED
;
334 msg
.adv_router
= NULL
;
338 eigrp_fsm_event(&msg
);
344 int eigrp_if_down(struct eigrp_interface
*ei
)
346 struct listnode
*node
, *nnode
;
347 struct eigrp_neighbor
*nbr
;
352 /* Shutdown packet reception and sending */
354 THREAD_OFF(ei
->t_hello
);
356 eigrp_if_stream_unset(ei
);
358 /*Set infinite metrics to routes learned by this interface and start
360 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
361 eigrp_nbr_delete(nbr
);
367 void eigrp_if_stream_set(struct eigrp_interface
*ei
)
369 /* set output fifo queue. */
370 if (ei
->obuf
== NULL
)
371 ei
->obuf
= eigrp_fifo_new();
374 void eigrp_if_stream_unset(struct eigrp_interface
*ei
)
376 struct eigrp
*eigrp
= ei
->eigrp
;
379 eigrp_fifo_free(ei
->obuf
);
382 if (ei
->on_write_q
) {
383 listnode_delete(eigrp
->oi_write_q
, ei
);
384 if (list_isempty(eigrp
->oi_write_q
))
385 thread_cancel(eigrp
->t_write
);
391 void eigrp_if_set_multicast(struct eigrp_interface
*ei
)
393 if ((EIGRP_IF_PASSIVE_STATUS(ei
) == EIGRP_IF_ACTIVE
)) {
394 /* The interface should belong to the EIGRP-all-routers group.
396 if (!EI_MEMBER_CHECK(ei
, MEMBER_ALLROUTERS
)
397 && (eigrp_if_add_allspfrouters(ei
->eigrp
, ei
->address
,
400 /* Set the flag only if the system call to join
402 EI_MEMBER_JOINED(ei
, MEMBER_ALLROUTERS
);
404 /* The interface should NOT belong to the EIGRP-all-routers
406 if (EI_MEMBER_CHECK(ei
, MEMBER_ALLROUTERS
)) {
407 /* Only actually drop if this is the last reference */
408 if (EI_MEMBER_COUNT(ei
, MEMBER_ALLROUTERS
) == 1)
409 eigrp_if_drop_allspfrouters(ei
->eigrp
,
412 /* Unset the flag regardless of whether the system call
414 the group succeeded, since it's much safer to assume
416 we are not a member. */
417 EI_MEMBER_LEFT(ei
, MEMBER_ALLROUTERS
);
422 u_char
eigrp_default_iftype(struct interface
*ifp
)
424 if (if_is_pointopoint(ifp
))
425 return EIGRP_IFTYPE_POINTOPOINT
;
426 else if (if_is_loopback(ifp
))
427 return EIGRP_IFTYPE_LOOPBACK
;
429 return EIGRP_IFTYPE_BROADCAST
;
432 void eigrp_if_free(struct eigrp_interface
*ei
, int source
)
434 struct prefix dest_addr
;
435 struct eigrp_prefix_entry
*pe
;
436 struct eigrp
*eigrp
= eigrp_lookup();
438 if (source
== INTERFACE_DOWN_BY_VTY
) {
439 THREAD_OFF(ei
->t_hello
);
440 eigrp_hello_send(ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN
, NULL
);
443 dest_addr
= *ei
->connected
->address
;
444 apply_mask(&dest_addr
);
445 pe
= eigrp_topology_table_lookup_ipv4(eigrp
->topology_table
,
448 eigrp_prefix_entry_delete(eigrp
->topology_table
, pe
);
452 list_delete(ei
->nbrs
);
453 eigrp_delete_from_if(ei
->ifp
, ei
);
454 listnode_delete(ei
->eigrp
->eiflist
, ei
);
456 thread_cancel_event(master
, ei
);
458 memset(ei
, 0, sizeof(*ei
));
459 XFREE(MTYPE_EIGRP_IF
, ei
);
462 static void eigrp_delete_from_if(struct interface
*ifp
,
463 struct eigrp_interface
*ei
)
465 struct route_node
*rn
;
469 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
471 rn
= route_node_lookup(IF_OIFS(ei
->ifp
), &p
);
475 route_unlock_node(rn
);
476 route_unlock_node(rn
);
479 /* Simulate down/up on the interface. This is needed, for example, when
481 void eigrp_if_reset(struct interface
*ifp
)
483 struct route_node
*rn
;
485 for (rn
= route_top(IF_OIFS(ifp
)); rn
; rn
= route_next(rn
)) {
486 struct eigrp_interface
*ei
;
488 if ((ei
= rn
->info
) == NULL
)
496 struct eigrp_interface
*eigrp_if_lookup_by_local_addr(struct eigrp
*eigrp
,
497 struct interface
*ifp
,
498 struct in_addr address
)
500 struct listnode
*node
;
501 struct eigrp_interface
*ei
;
503 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
504 if (ifp
&& ei
->ifp
!= ifp
)
507 if (IPV4_ADDR_SAME(&address
, &ei
->address
->u
.prefix4
))
515 * @fn eigrp_if_lookup_by_name
517 * @param[in] eigrp EIGRP process
518 * @param[in] if_name Name of the interface
520 * @return struct eigrp_interface *
523 * Function is used for lookup interface by name.
525 struct eigrp_interface
*eigrp_if_lookup_by_name(struct eigrp
*eigrp
,
528 struct eigrp_interface
*ei
;
529 struct listnode
*node
;
531 /* iterate over all eigrp interfaces */
532 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
533 /* compare int name with eigrp interface's name */
534 if (strcmp(ei
->ifp
->name
, if_name
) == 0) {
542 /* determine receiving interface by ifp and source address */
543 struct eigrp_interface
*eigrp_if_lookup_recv_if(struct eigrp
*eigrp
,
545 struct interface
*ifp
)
547 struct route_node
*rn
;
549 struct eigrp_interface
*ei
, *match
;
551 addr
.family
= AF_INET
;
552 addr
.u
.prefix4
= src
;
553 addr
.prefixlen
= IPV4_MAX_BITLEN
;
557 for (rn
= route_top(IF_OIFS(ifp
)); rn
; rn
= route_next(rn
)) {
560 if (!ei
) /* oi can be NULL for PtP aliases */
563 if (if_is_loopback(ei
->ifp
))
566 if (prefix_match(CONNECTED_PREFIX(ei
->connected
),
568 if ((match
== NULL
) || (match
->address
->prefixlen
569 < ei
->address
->prefixlen
))
577 u_int32_t
eigrp_bandwidth_to_scaled(u_int32_t bandwidth
)
579 uint64_t temp_bandwidth
= (256ull * 10000000) / bandwidth
;
581 temp_bandwidth
= temp_bandwidth
< EIGRP_MAX_METRIC
? temp_bandwidth
584 return (u_int32_t
)temp_bandwidth
;
587 u_int32_t
eigrp_scaled_to_bandwidth(u_int32_t scaled
)
589 uint64_t temp_scaled
= scaled
* (256ull * 10000000);
592 temp_scaled
< EIGRP_MAX_METRIC
? temp_scaled
: EIGRP_MAX_METRIC
;
594 return (u_int32_t
)temp_scaled
;
597 u_int32_t
eigrp_delay_to_scaled(u_int32_t delay
)
602 u_int32_t
eigrp_scaled_to_delay(u_int32_t scaled
)