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"
57 #include "eigrpd/eigrp_dump.h"
59 struct eigrp_interface
*eigrp_if_new(struct eigrp
*eigrp
, struct interface
*ifp
,
62 struct eigrp_interface
*ei
= ifp
->info
;
68 ei
= XCALLOC(MTYPE_EIGRP_IF
, sizeof(struct eigrp_interface
));
70 /* Set zebra interface pointer. */
72 prefix_copy(&ei
->address
, p
);
75 listnode_add(eigrp
->eiflist
, ei
);
77 ei
->type
= EIGRP_IFTYPE_BROADCAST
;
79 /* Initialize neighbor list. */
80 ei
->nbrs
= list_new();
82 ei
->crypt_seqnum
= time(NULL
);
84 /* Initialize lists */
85 for (i
= 0; i
< EIGRP_FILTER_MAX
; i
++) {
88 ei
->routemap
[i
] = NULL
;
93 ei
->params
.v_hello
= EIGRP_HELLO_INTERVAL_DEFAULT
;
94 ei
->params
.v_wait
= EIGRP_HOLD_INTERVAL_DEFAULT
;
95 ei
->params
.bandwidth
= EIGRP_BANDWIDTH_DEFAULT
;
96 ei
->params
.delay
= EIGRP_DELAY_DEFAULT
;
97 ei
->params
.reliability
= EIGRP_RELIABILITY_DEFAULT
;
98 ei
->params
.load
= EIGRP_LOAD_DEFAULT
;
99 ei
->params
.auth_type
= EIGRP_AUTH_TYPE_NONE
;
100 ei
->params
.auth_keychain
= NULL
;
105 int eigrp_if_delete_hook(struct interface
*ifp
)
107 struct eigrp_interface
*ei
= ifp
->info
;
113 list_delete(&ei
->nbrs
);
116 listnode_delete(eigrp
->eiflist
, ei
);
118 eigrp_fifo_free(ei
->obuf
);
120 XFREE(MTYPE_EIGRP_IF_INFO
, ifp
->info
);
126 static int eigrp_ifp_create(struct interface
*ifp
)
128 struct eigrp_interface
*ei
= ifp
->info
;
133 ei
->params
.type
= eigrp_default_iftype(ifp
);
135 eigrp_if_update(ifp
);
140 static int eigrp_ifp_up(struct interface
*ifp
)
142 /* Interface is already up. */
143 if (if_is_operative(ifp
)) {
144 /* Temporarily keep ifp values. */
145 struct interface if_tmp
;
146 memcpy(&if_tmp
, ifp
, sizeof(struct interface
));
148 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
149 zlog_debug("Zebra: Interface[%s] state update.",
152 if (if_tmp
.bandwidth
!= ifp
->bandwidth
) {
153 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
155 "Zebra: Interface[%s] bandwidth change %d -> %d.",
156 ifp
->name
, if_tmp
.bandwidth
,
159 // eigrp_if_recalculate_output_cost (ifp);
162 if (if_tmp
.mtu
!= ifp
->mtu
) {
163 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
165 "Zebra: Interface[%s] MTU change %u -> %u.",
166 ifp
->name
, if_tmp
.mtu
, ifp
->mtu
);
168 /* Must reset the interface (simulate down/up) when MTU
175 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
176 zlog_debug("Zebra: Interface[%s] state change to up.",
180 eigrp_if_up(ifp
->info
);
185 static int eigrp_ifp_down(struct interface
*ifp
)
187 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
188 zlog_debug("Zebra: Interface[%s] state change to down.",
192 eigrp_if_down(ifp
->info
);
197 static int eigrp_ifp_destroy(struct interface
*ifp
)
200 zlog_warn("Zebra: got delete of %s, but interface is still up",
203 if (IS_DEBUG_EIGRP(zebra
, ZEBRA_INTERFACE
))
205 "Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
206 ifp
->name
, ifp
->ifindex
, (unsigned long long)ifp
->flags
,
207 ifp
->metric
, ifp
->mtu
);
210 eigrp_if_free(ifp
->info
, INTERFACE_DOWN_BY_ZEBRA
);
215 struct list
*eigrp_iflist
;
217 void eigrp_if_init(void)
219 if_zapi_callbacks(eigrp_ifp_create
, eigrp_ifp_up
,
220 eigrp_ifp_down
, eigrp_ifp_destroy
);
221 /* Initialize Zebra interface data structure. */
222 // hook_register_prio(if_add, 0, eigrp_if_new);
223 hook_register_prio(if_del
, 0, eigrp_if_delete_hook
);
227 void eigrp_del_if_params(struct eigrp_if_params
*eip
)
229 if (eip
->auth_keychain
)
230 free(eip
->auth_keychain
);
233 int eigrp_if_up(struct eigrp_interface
*ei
)
235 struct eigrp_prefix_entry
*pe
;
236 struct eigrp_nexthop_entry
*ne
;
237 struct eigrp_metrics metric
;
238 struct eigrp_interface
*ei2
;
239 struct listnode
*node
, *nnode
;
246 eigrp_adjust_sndbuflen(eigrp
, ei
->ifp
->mtu
);
248 eigrp_if_stream_set(ei
);
250 /* Set multicast memberships appropriately for new state. */
251 eigrp_if_set_multicast(ei
);
253 thread_add_event(master
, eigrp_hello_timer
, ei
, (1), NULL
);
256 metric
.bandwidth
= eigrp_bandwidth_to_scaled(ei
->params
.bandwidth
);
257 metric
.delay
= eigrp_delay_to_scaled(ei
->params
.delay
);
258 metric
.load
= ei
->params
.load
;
259 metric
.reliability
= ei
->params
.reliability
;
260 metric
.mtu
[0] = 0xDC;
261 metric
.mtu
[1] = 0x05;
262 metric
.mtu
[2] = 0x00;
263 metric
.hop_count
= 0;
267 /*Add connected entry to topology table*/
269 ne
= eigrp_nexthop_entry_new();
271 ne
->reported_metric
= metric
;
272 ne
->total_metric
= metric
;
273 ne
->distance
= eigrp_calculate_metrics(eigrp
, metric
);
274 ne
->reported_distance
= 0;
275 ne
->adv_router
= eigrp
->neighbor_self
;
276 ne
->flags
= EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG
;
278 struct prefix dest_addr
;
280 dest_addr
= ei
->address
;
281 apply_mask(&dest_addr
);
282 pe
= eigrp_topology_table_lookup_ipv4(eigrp
->topology_table
,
286 pe
= eigrp_prefix_entry_new();
287 pe
->serno
= eigrp
->serno
;
288 pe
->destination
= (struct prefix
*)prefix_ipv4_new();
289 prefix_copy(pe
->destination
, &dest_addr
);
291 pe
->nt
= EIGRP_TOPOLOGY_TYPE_CONNECTED
;
294 pe
->reported_metric
= metric
;
295 pe
->state
= EIGRP_FSM_STATE_PASSIVE
;
296 pe
->fdistance
= eigrp_calculate_metrics(eigrp
, metric
);
297 pe
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
298 eigrp_prefix_entry_add(eigrp
->topology_table
, pe
);
299 listnode_add(eigrp
->topology_changes_internalIPV4
, pe
);
301 eigrp_nexthop_entry_add(eigrp
, pe
, ne
);
303 for (ALL_LIST_ELEMENTS(eigrp
->eiflist
, node
, nnode
, ei2
)) {
304 eigrp_update_send(ei2
);
307 pe
->req_action
&= ~EIGRP_FSM_NEED_UPDATE
;
308 listnode_delete(eigrp
->topology_changes_internalIPV4
, pe
);
310 struct eigrp_fsm_action_message msg
;
313 eigrp_nexthop_entry_add(eigrp
, pe
, ne
);
315 msg
.packet_type
= EIGRP_OPC_UPDATE
;
317 msg
.data_type
= EIGRP_CONNECTED
;
318 msg
.adv_router
= NULL
;
322 eigrp_fsm_event(&msg
);
328 int eigrp_if_down(struct eigrp_interface
*ei
)
330 struct listnode
*node
, *nnode
;
331 struct eigrp_neighbor
*nbr
;
336 /* Shutdown packet reception and sending */
338 THREAD_OFF(ei
->t_hello
);
340 eigrp_if_stream_unset(ei
);
342 /*Set infinite metrics to routes learned by this interface and start
344 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node
, nnode
, nbr
)) {
345 eigrp_nbr_delete(nbr
);
351 void eigrp_if_stream_set(struct eigrp_interface
*ei
)
353 /* set output fifo queue. */
354 if (ei
->obuf
== NULL
)
355 ei
->obuf
= eigrp_fifo_new();
358 void eigrp_if_stream_unset(struct eigrp_interface
*ei
)
360 struct eigrp
*eigrp
= ei
->eigrp
;
362 if (ei
->on_write_q
) {
363 listnode_delete(eigrp
->oi_write_q
, ei
);
364 if (list_isempty(eigrp
->oi_write_q
))
365 thread_cancel(eigrp
->t_write
);
370 bool eigrp_if_is_passive(struct eigrp_interface
*ei
)
372 if (ei
->params
.passive_interface
== EIGRP_IF_ACTIVE
)
375 if (ei
->eigrp
->passive_interface_default
== EIGRP_IF_ACTIVE
)
381 void eigrp_if_set_multicast(struct eigrp_interface
*ei
)
383 if (!eigrp_if_is_passive(ei
)) {
384 /* The interface should belong to the EIGRP-all-routers group.
386 if (!ei
->member_allrouters
387 && (eigrp_if_add_allspfrouters(ei
->eigrp
, &ei
->address
,
390 /* Set the flag only if the system call to join
392 ei
->member_allrouters
= true;
394 /* The interface should NOT belong to the EIGRP-all-routers
396 if (ei
->member_allrouters
) {
397 /* Only actually drop if this is the last reference */
398 eigrp_if_drop_allspfrouters(ei
->eigrp
, &ei
->address
,
400 /* Unset the flag regardless of whether the system call
402 the group succeeded, since it's much safer to assume
404 we are not a member. */
405 ei
->member_allrouters
= false;
410 uint8_t eigrp_default_iftype(struct interface
*ifp
)
412 if (if_is_pointopoint(ifp
))
413 return EIGRP_IFTYPE_POINTOPOINT
;
414 else if (if_is_loopback(ifp
))
415 return EIGRP_IFTYPE_LOOPBACK
;
417 return EIGRP_IFTYPE_BROADCAST
;
420 void eigrp_if_free(struct eigrp_interface
*ei
, int source
)
422 struct prefix dest_addr
;
423 struct eigrp_prefix_entry
*pe
;
424 struct eigrp
*eigrp
= ei
->eigrp
;
426 if (source
== INTERFACE_DOWN_BY_VTY
) {
427 THREAD_OFF(ei
->t_hello
);
428 eigrp_hello_send(ei
, EIGRP_HELLO_GRACEFUL_SHUTDOWN
, NULL
);
431 dest_addr
= ei
->address
;
432 apply_mask(&dest_addr
);
433 pe
= eigrp_topology_table_lookup_ipv4(eigrp
->topology_table
,
436 eigrp_prefix_entry_delete(eigrp
, eigrp
->topology_table
, pe
);
440 listnode_delete(ei
->eigrp
->eiflist
, ei
);
443 /* Simulate down/up on the interface. This is needed, for example, when
445 void eigrp_if_reset(struct interface
*ifp
)
447 struct eigrp_interface
*ei
= ifp
->info
;
456 struct eigrp_interface
*eigrp_if_lookup_by_local_addr(struct eigrp
*eigrp
,
457 struct interface
*ifp
,
458 struct in_addr address
)
460 struct listnode
*node
;
461 struct eigrp_interface
*ei
;
463 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
464 if (ifp
&& ei
->ifp
!= ifp
)
467 if (IPV4_ADDR_SAME(&address
, &ei
->address
.u
.prefix4
))
475 * @fn eigrp_if_lookup_by_name
477 * @param[in] eigrp EIGRP process
478 * @param[in] if_name Name of the interface
480 * @return struct eigrp_interface *
483 * Function is used for lookup interface by name.
485 struct eigrp_interface
*eigrp_if_lookup_by_name(struct eigrp
*eigrp
,
488 struct eigrp_interface
*ei
;
489 struct listnode
*node
;
491 /* iterate over all eigrp interfaces */
492 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
493 /* compare int name with eigrp interface's name */
494 if (strcmp(ei
->ifp
->name
, if_name
) == 0) {
502 uint32_t eigrp_bandwidth_to_scaled(uint32_t bandwidth
)
504 uint64_t temp_bandwidth
= (256ull * 10000000) / bandwidth
;
506 temp_bandwidth
= temp_bandwidth
< EIGRP_MAX_METRIC
? temp_bandwidth
509 return (uint32_t)temp_bandwidth
;
512 uint32_t eigrp_scaled_to_bandwidth(uint32_t scaled
)
514 uint64_t temp_scaled
= scaled
* (256ull * 10000000);
517 temp_scaled
< EIGRP_MAX_METRIC
? temp_scaled
: EIGRP_MAX_METRIC
;
519 return (uint32_t)temp_scaled
;
522 uint32_t eigrp_delay_to_scaled(uint32_t delay
)
527 uint32_t eigrp_scaled_to_delay(uint32_t scaled
)