1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * EIGRP Topology Table.
4 * Copyright (C) 2013-2016
25 #include "lib_errors.h"
27 #include "eigrpd/eigrp_types.h"
28 #include "eigrpd/eigrp_structs.h"
29 #include "eigrpd/eigrpd.h"
30 #include "eigrpd/eigrp_interface.h"
31 #include "eigrpd/eigrp_neighbor.h"
32 #include "eigrpd/eigrp_packet.h"
33 #include "eigrpd/eigrp_zebra.h"
34 #include "eigrpd/eigrp_vty.h"
35 #include "eigrpd/eigrp_network.h"
36 #include "eigrpd/eigrp_dump.h"
37 #include "eigrpd/eigrp_topology.h"
38 #include "eigrpd/eigrp_fsm.h"
39 #include "eigrpd/eigrp_metric.h"
41 DEFINE_MTYPE_STATIC(EIGRPD
, EIGRP_ROUTE_DESCRIPTOR
, "EIGRP Nexthop Entry");
42 DEFINE_MTYPE(EIGRPD
, EIGRP_PREFIX_DESCRIPTOR
, "EIGRP Prefix");
44 static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor
*rd1
,
45 struct eigrp_route_descriptor
*rd2
);
48 * Returns linkedlist used as topology table
49 * cmp - assigned function for comparing topology nodes
50 * del - assigned function executed before deleting topology node by list
53 struct route_table
*eigrp_topology_new(void)
55 return route_table_init();
59 * Returns new created toplogy node
60 * cmp - assigned function for comparing topology entry
62 struct eigrp_prefix_descriptor
*eigrp_prefix_descriptor_new(void)
64 struct eigrp_prefix_descriptor
*new;
65 new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR
,
66 sizeof(struct eigrp_prefix_descriptor
));
67 new->entries
= list_new();
68 new->rij
= list_new();
69 new->entries
->cmp
= (int (*)(void *, void *))eigrp_route_descriptor_cmp
;
70 new->distance
= new->fdistance
= new->rdistance
= EIGRP_MAX_METRIC
;
71 new->destination
= NULL
;
77 * Topology entry comparison
79 static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor
*entry1
,
80 struct eigrp_route_descriptor
*entry2
)
82 if (entry1
->distance
< entry2
->distance
)
84 if (entry1
->distance
> entry2
->distance
)
91 * Returns new topology entry
94 struct eigrp_route_descriptor
*eigrp_route_descriptor_new(void)
96 struct eigrp_route_descriptor
*new;
98 new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR
,
99 sizeof(struct eigrp_route_descriptor
));
100 new->reported_distance
= EIGRP_MAX_METRIC
;
101 new->distance
= EIGRP_MAX_METRIC
;
107 * Freeing topology table list
109 void eigrp_topology_free(struct eigrp
*eigrp
, struct route_table
*table
)
111 eigrp_topology_delete_all(eigrp
, table
);
112 route_table_finish(table
);
116 * Adding topology node to topology table
118 void eigrp_prefix_descriptor_add(struct route_table
*topology
,
119 struct eigrp_prefix_descriptor
*pe
)
121 struct route_node
*rn
;
123 rn
= route_node_get(topology
, pe
->destination
);
125 if (IS_DEBUG_EIGRP_EVENT
)
127 "%s: %pFX Should we have found this entry in the topo table?",
128 __func__
, pe
->destination
);
129 route_unlock_node(rn
);
136 * Adding topology entry to topology node
138 void eigrp_route_descriptor_add(struct eigrp
*eigrp
,
139 struct eigrp_prefix_descriptor
*node
,
140 struct eigrp_route_descriptor
*entry
)
142 struct list
*l
= list_new();
144 listnode_add(l
, entry
);
146 if (listnode_lookup(node
->entries
, entry
) == NULL
) {
147 listnode_add_sort(node
->entries
, entry
);
148 entry
->prefix
= node
;
150 eigrp_zebra_route_add(eigrp
, node
->destination
,
158 * Deleting topology node from topology table
160 void eigrp_prefix_descriptor_delete(struct eigrp
*eigrp
,
161 struct route_table
*table
,
162 struct eigrp_prefix_descriptor
*pe
)
164 struct eigrp_route_descriptor
*ne
;
165 struct listnode
*node
, *nnode
;
166 struct route_node
*rn
;
171 rn
= route_node_lookup(table
, pe
->destination
);
176 * Emergency removal of the node from this list.
179 listnode_delete(eigrp
->topology_changes_internalIPV4
, pe
);
181 for (ALL_LIST_ELEMENTS(pe
->entries
, node
, nnode
, ne
))
182 eigrp_route_descriptor_delete(eigrp
, pe
, ne
);
183 list_delete(&pe
->entries
);
184 list_delete(&pe
->rij
);
185 eigrp_zebra_route_delete(eigrp
, pe
->destination
);
186 prefix_free(&pe
->destination
);
189 route_unlock_node(rn
); // Lookup above
190 route_unlock_node(rn
); // Initial creation
191 XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR
, pe
);
195 * Deleting topology entry from topology node
197 void eigrp_route_descriptor_delete(struct eigrp
*eigrp
,
198 struct eigrp_prefix_descriptor
*node
,
199 struct eigrp_route_descriptor
*entry
)
201 if (listnode_lookup(node
->entries
, entry
) != NULL
) {
202 listnode_delete(node
->entries
, entry
);
203 eigrp_zebra_route_delete(eigrp
, node
->destination
);
204 XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR
, entry
);
209 * Deleting all nodes from topology table
211 void eigrp_topology_delete_all(struct eigrp
*eigrp
,
212 struct route_table
*topology
)
214 struct route_node
*rn
;
215 struct eigrp_prefix_descriptor
*pe
;
217 for (rn
= route_top(topology
); rn
; rn
= route_next(rn
)) {
223 eigrp_prefix_descriptor_delete(eigrp
, topology
, pe
);
227 struct eigrp_prefix_descriptor
*
228 eigrp_topology_table_lookup_ipv4(struct route_table
*table
,
229 struct prefix
*address
)
231 struct eigrp_prefix_descriptor
*pe
;
232 struct route_node
*rn
;
234 rn
= route_node_lookup(table
, address
);
240 route_unlock_node(rn
);
246 * For a future optimization, put the successor list into it's
247 * own separate list from the full list?
249 * That way we can clean up all the list_new and list_delete's
250 * that we are doing. DBS
253 eigrp_topology_get_successor(struct eigrp_prefix_descriptor
*table_node
)
255 struct list
*successors
= list_new();
256 struct eigrp_route_descriptor
*data
;
257 struct listnode
*node1
, *node2
;
259 for (ALL_LIST_ELEMENTS(table_node
->entries
, node1
, node2
, data
)) {
260 if (data
->flags
& EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG
) {
261 listnode_add(successors
, data
);
266 * If we have no successors return NULL
268 if (!successors
->count
) {
269 list_delete(&successors
);
277 eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor
*table_node
,
278 unsigned int maxpaths
)
280 struct list
*successors
= eigrp_topology_get_successor(table_node
);
282 if (successors
&& successors
->count
> maxpaths
) {
284 struct listnode
*node
= listtail(successors
);
286 list_delete_node(successors
, node
);
288 } while (successors
->count
> maxpaths
);
294 struct eigrp_route_descriptor
*
295 eigrp_route_descriptor_lookup(struct list
*entries
, struct eigrp_neighbor
*nbr
)
297 struct eigrp_route_descriptor
*data
;
298 struct listnode
*node
, *nnode
;
299 for (ALL_LIST_ELEMENTS(entries
, node
, nnode
, data
)) {
300 if (data
->adv_router
== nbr
) {
308 /* Lookup all prefixes from specified neighbor */
309 struct list
*eigrp_neighbor_prefixes_lookup(struct eigrp
*eigrp
,
310 struct eigrp_neighbor
*nbr
)
312 struct listnode
*node2
, *node22
;
313 struct eigrp_route_descriptor
*entry
;
314 struct eigrp_prefix_descriptor
*pe
;
315 struct route_node
*rn
;
317 /* create new empty list for prefixes storage */
318 struct list
*prefixes
= list_new();
320 /* iterate over all prefixes in topology table */
321 for (rn
= route_top(eigrp
->topology_table
); rn
; rn
= route_next(rn
)) {
325 /* iterate over all neighbor entry in prefix */
326 for (ALL_LIST_ELEMENTS(pe
->entries
, node2
, node22
, entry
)) {
327 /* if entry is from specified neighbor, add to list */
328 if (entry
->adv_router
== nbr
) {
329 listnode_add(prefixes
, pe
);
334 /* return list of prefixes from specified neighbor */
339 eigrp_topology_update_distance(struct eigrp_fsm_action_message
*msg
)
341 struct eigrp
*eigrp
= msg
->eigrp
;
342 struct eigrp_prefix_descriptor
*prefix
= msg
->prefix
;
343 struct eigrp_route_descriptor
*entry
= msg
->entry
;
344 enum metric_change change
= METRIC_SAME
;
345 uint32_t new_reported_distance
;
349 switch (msg
->data_type
) {
350 case EIGRP_CONNECTED
:
351 if (prefix
->nt
== EIGRP_TOPOLOGY_TYPE_CONNECTED
)
354 change
= METRIC_DECREASE
;
357 if (prefix
->nt
== EIGRP_TOPOLOGY_TYPE_CONNECTED
) {
358 change
= METRIC_INCREASE
;
361 if (eigrp_metrics_is_same(msg
->metrics
,
362 entry
->reported_metric
)) {
363 return change
; // No change
366 new_reported_distance
=
367 eigrp_calculate_metrics(eigrp
, msg
->metrics
);
369 if (entry
->reported_distance
< new_reported_distance
) {
370 change
= METRIC_INCREASE
;
373 change
= METRIC_DECREASE
;
375 entry
->reported_metric
= msg
->metrics
;
376 entry
->reported_distance
= new_reported_distance
;
377 eigrp_calculate_metrics(eigrp
, msg
->metrics
);
378 entry
->distance
= eigrp_calculate_total_metrics(eigrp
, entry
);
381 if (prefix
->nt
== EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL
) {
382 if (eigrp_metrics_is_same(msg
->metrics
,
383 entry
->reported_metric
))
386 change
= METRIC_INCREASE
;
391 flog_err(EC_LIB_DEVELOPMENT
, "%s: Please implement handler",
397 * Move to correct position in list according to new distance
399 listnode_delete(prefix
->entries
, entry
);
400 listnode_add_sort(prefix
->entries
, entry
);
405 void eigrp_topology_update_all_node_flags(struct eigrp
*eigrp
)
407 struct eigrp_prefix_descriptor
*pe
;
408 struct route_node
*rn
;
413 for (rn
= route_top(eigrp
->topology_table
); rn
; rn
= route_next(rn
)) {
419 eigrp_topology_update_node_flags(eigrp
, pe
);
423 void eigrp_topology_update_node_flags(struct eigrp
*eigrp
,
424 struct eigrp_prefix_descriptor
*dest
)
426 struct listnode
*node
;
427 struct eigrp_route_descriptor
*entry
;
429 for (ALL_LIST_ELEMENTS_RO(dest
->entries
, node
, entry
)) {
430 if (entry
->reported_distance
< dest
->fdistance
) {
431 // is feasible successor, can be successor
432 if (((uint64_t)entry
->distance
433 <= (uint64_t)dest
->distance
434 * (uint64_t)eigrp
->variance
)
435 && entry
->distance
!= EIGRP_MAX_METRIC
) {
438 EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG
;
440 ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG
;
442 // is feasible successor only
444 EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG
;
446 ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG
;
449 entry
->flags
&= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG
;
450 entry
->flags
&= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG
;
455 void eigrp_update_routing_table(struct eigrp
*eigrp
,
456 struct eigrp_prefix_descriptor
*prefix
)
458 struct list
*successors
;
459 struct listnode
*node
;
460 struct eigrp_route_descriptor
*entry
;
462 successors
= eigrp_topology_get_successor_max(prefix
, eigrp
->max_paths
);
465 eigrp_zebra_route_add(eigrp
, prefix
->destination
, successors
,
467 for (ALL_LIST_ELEMENTS_RO(successors
, node
, entry
))
468 entry
->flags
|= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG
;
470 list_delete(&successors
);
472 eigrp_zebra_route_delete(eigrp
, prefix
->destination
);
473 for (ALL_LIST_ELEMENTS_RO(prefix
->entries
, node
, entry
))
474 entry
->flags
&= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG
;
478 void eigrp_topology_neighbor_down(struct eigrp
*eigrp
,
479 struct eigrp_neighbor
*nbr
)
481 struct listnode
*node2
, *node22
;
482 struct eigrp_prefix_descriptor
*pe
;
483 struct eigrp_route_descriptor
*entry
;
484 struct route_node
*rn
;
486 for (rn
= route_top(eigrp
->topology_table
); rn
; rn
= route_next(rn
)) {
492 for (ALL_LIST_ELEMENTS(pe
->entries
, node2
, node22
, entry
)) {
493 struct eigrp_fsm_action_message msg
;
495 if (entry
->adv_router
!= nbr
)
498 memset(&msg
, 0, sizeof(msg
));
499 msg
.metrics
.delay
= EIGRP_MAX_METRIC
;
500 msg
.packet_type
= EIGRP_OPC_UPDATE
;
502 msg
.data_type
= EIGRP_INT
;
503 msg
.adv_router
= nbr
;
506 eigrp_fsm_event(&msg
);
510 eigrp_query_send_all(eigrp
);
511 eigrp_update_send_all(eigrp
, nbr
->ei
);
514 void eigrp_update_topology_table_prefix(struct eigrp
*eigrp
,
515 struct route_table
*table
,
516 struct eigrp_prefix_descriptor
*prefix
)
518 struct listnode
*node1
, *node2
;
520 struct eigrp_route_descriptor
*entry
;
521 for (ALL_LIST_ELEMENTS(prefix
->entries
, node1
, node2
, entry
)) {
522 if (entry
->distance
== EIGRP_MAX_METRIC
) {
523 eigrp_route_descriptor_delete(eigrp
, prefix
, entry
);
526 if (prefix
->distance
== EIGRP_MAX_METRIC
527 && prefix
->nt
!= EIGRP_TOPOLOGY_TYPE_CONNECTED
) {
528 eigrp_prefix_descriptor_delete(eigrp
, table
, prefix
);