2 * EIGRP Topology Table.
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
28 * along with GNU Zebra; see the file COPYING. If not, write to the Free
29 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
42 #include "eigrpd/eigrp_structs.h"
43 #include "eigrpd/eigrpd.h"
44 #include "eigrpd/eigrp_interface.h"
45 #include "eigrpd/eigrp_neighbor.h"
46 #include "eigrpd/eigrp_packet.h"
47 #include "eigrpd/eigrp_zebra.h"
48 #include "eigrpd/eigrp_vty.h"
49 #include "eigrpd/eigrp_network.h"
50 #include "eigrpd/eigrp_dump.h"
51 #include "eigrpd/eigrp_topology.h"
52 #include "eigrpd/eigrp_fsm.h"
53 #include "eigrpd/eigrp_memory.h"
55 static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry
*, struct eigrp_prefix_entry
*);
56 static void eigrp_prefix_entry_del(struct eigrp_prefix_entry
*);
57 static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry
*,
58 struct eigrp_neighbor_entry
*);
61 * Returns linkedlist used as topology table
62 * cmp - assigned function for comparing topology nodes
63 * del - assigned function executed before deleting topology node by list function
68 struct list
* new = list_new();
70 (*)(void *, void *)) eigrp_prefix_entry_cmp
;
72 (*)(void *)) eigrp_prefix_entry_del
;
78 * Topology node comparison
82 eigrp_prefix_entry_cmp(struct eigrp_prefix_entry
*node1
,
83 struct eigrp_prefix_entry
*node2
)
85 if (node1
->af
== AF_INET
)
87 if (node2
->af
== AF_INET
)
89 if (node1
->destination_ipv4
->prefix
.s_addr
90 < node2
->destination_ipv4
->prefix
.s_addr
)
92 return -1; // if it belong above node2
96 if (node1
->destination_ipv4
->prefix
.s_addr
97 > node2
->destination_ipv4
->prefix
.s_addr
)
99 return 1; //if it belongs under node2
103 return 0; // same value... ERROR...in case of adding same prefix again
113 { // TODO check if the prefix dont exists
114 return 1; // add to end
119 * Topology node delete
123 eigrp_prefix_entry_del(struct eigrp_prefix_entry
*node
)
125 list_delete_all_node(node
->entries
);
126 list_free(node
->entries
);
130 * Returns new created toplogy node
131 * cmp - assigned function for comparing topology entry
133 struct eigrp_prefix_entry
*
134 eigrp_prefix_entry_new()
136 struct eigrp_prefix_entry
*new;
137 new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY
, sizeof(struct eigrp_prefix_entry
));
138 new->entries
= list_new();
139 new->rij
= list_new();
140 new->entries
->cmp
= (int (*)(void *, void *))eigrp_neighbor_entry_cmp
;
141 new->distance
= new->fdistance
= new->rdistance
= EIGRP_MAX_METRIC
;
142 new->destination_ipv4
= NULL
;
143 new->destination_ipv6
= NULL
;
149 * Topology entry comparison
152 eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry
*entry1
,
153 struct eigrp_neighbor_entry
*entry2
)
155 if (entry1
->distance
< entry2
->distance
) // parameter used in list_add_sort ()
156 return -1; // actually set to sort by distance
157 if (entry1
->distance
> entry2
->distance
)
164 * Returns new topology entry
167 struct eigrp_neighbor_entry
*
168 eigrp_neighbor_entry_new()
170 struct eigrp_neighbor_entry
*new;
172 new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY
,
173 sizeof(struct eigrp_neighbor_entry
));
174 new->reported_distance
= EIGRP_MAX_METRIC
;
175 new->distance
= EIGRP_MAX_METRIC
;
181 * Freeing topology table list
184 eigrp_topology_free(struct list
*list
)
190 * Deleting all topology nodes in table
193 eigrp_topology_cleanup(struct list
*topology
)
197 eigrp_topology_delete_all(topology
);
201 * Adding topology node to topology table
204 eigrp_prefix_entry_add(struct list
*topology
, struct eigrp_prefix_entry
*node
)
206 if (listnode_lookup(topology
, node
) == NULL
)
208 listnode_add_sort(topology
, node
);
213 * Adding topology entry to topology node
216 eigrp_neighbor_entry_add(struct eigrp_prefix_entry
*node
,
217 struct eigrp_neighbor_entry
*entry
)
219 if (listnode_lookup(node
->entries
, entry
) == NULL
)
221 listnode_add_sort(node
->entries
, entry
);
222 entry
->prefix
= node
;
227 * Deleting topology node from topology table
230 eigrp_prefix_entry_delete(struct list
*topology
,
231 struct eigrp_prefix_entry
*node
)
233 struct eigrp
*eigrp
= eigrp_lookup ();
236 * Emergency removal of the node from this list.
239 listnode_delete(eigrp
->topology_changes_internalIPV4
, node
);
241 if (listnode_lookup(topology
, node
) != NULL
)
243 list_delete_all_node(node
->entries
);
244 list_free(node
->entries
);
245 list_free(node
->rij
);
246 listnode_delete(topology
, node
);
247 XFREE(MTYPE_EIGRP_PREFIX_ENTRY
,node
);
252 * Deleting topology entry from topology node
255 eigrp_neighbor_entry_delete(struct eigrp_prefix_entry
*node
,
256 struct eigrp_neighbor_entry
*entry
)
258 if (listnode_lookup(node
->entries
, entry
) != NULL
)
260 listnode_delete(node
->entries
, entry
);
261 XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY
,entry
);
266 * Deleting all nodes from topology table
269 eigrp_topology_delete_all(struct list
*topology
)
271 list_delete_all_node(topology
);
275 * Return 0 if topology is not empty
279 eigrp_topology_table_isempty(struct list
*topology
)
287 struct eigrp_prefix_entry
*
288 eigrp_topology_table_lookup_ipv4(struct list
*topology_table
,
289 struct prefix_ipv4
* address
)
291 struct eigrp_prefix_entry
*data
;
292 struct listnode
*node
;
293 for (ALL_LIST_ELEMENTS_RO(topology_table
, node
, data
))
295 if ((data
->af
== AF_INET
)
296 && (data
->destination_ipv4
->prefix
.s_addr
== address
->prefix
.s_addr
)
297 && (data
->destination_ipv4
->prefixlen
== address
->prefixlen
))
305 * For a future optimization, put the successor list into it's
306 * own separate list from the full list?
308 * That way we can clean up all the list_new and list_delete's
309 * that we are doing. DBS
312 eigrp_topology_get_successor(struct eigrp_prefix_entry
*table_node
)
314 struct list
*successors
= list_new();
315 struct eigrp_neighbor_entry
*data
;
316 struct listnode
*node1
, *node2
;
318 for (ALL_LIST_ELEMENTS(table_node
->entries
, node1
, node2
, data
))
320 if (data
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)
322 listnode_add(successors
, data
);
327 * If we have no successors return NULL
329 if (!successors
->count
)
331 list_delete(successors
);
339 eigrp_topology_get_successor_max(struct eigrp_prefix_entry
*table_node
,
340 unsigned int maxpaths
)
342 struct list
*successors
= eigrp_topology_get_successor(table_node
);
344 if (successors
&& successors
->count
> maxpaths
)
348 struct listnode
*node
= listtail(successors
);
350 list_delete_node(successors
, node
);
352 } while (successors
->count
> maxpaths
);
358 struct eigrp_neighbor_entry
*
359 eigrp_prefix_entry_lookup(struct list
*entries
, struct eigrp_neighbor
*nbr
)
361 struct eigrp_neighbor_entry
*data
;
362 struct listnode
*node
, *nnode
;
363 for (ALL_LIST_ELEMENTS(entries
, node
, nnode
, data
))
365 if (data
->adv_router
== nbr
)
374 /* Lookup all prefixes from specified neighbor */
376 eigrp_neighbor_prefixes_lookup(struct eigrp
*eigrp
, struct eigrp_neighbor
*nbr
)
378 struct listnode
*node1
, *node11
, *node2
, *node22
;
379 struct eigrp_prefix_entry
*prefix
;
380 struct eigrp_neighbor_entry
*entry
;
382 /* create new empty list for prefixes storage */
383 struct list
*prefixes
= list_new();
385 /* iterate over all prefixes in topology table */
386 for (ALL_LIST_ELEMENTS(eigrp
->topology_table
, node1
, node11
, prefix
))
388 /* iterate over all neighbor entry in prefix */
389 for (ALL_LIST_ELEMENTS(prefix
->entries
, node2
, node22
, entry
))
391 /* if entry is from specified neighbor, add to list */
392 if (entry
->adv_router
== nbr
)
394 listnode_add(prefixes
, prefix
);
399 /* return list of prefixes from specified neighbor */
404 eigrp_topology_update_distance(struct eigrp_fsm_action_message
*msg
)
406 struct eigrp
*eigrp
= msg
->eigrp
;
407 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
408 struct eigrp_neighbor_entry
*entry
= msg
->entry
;
412 struct TLV_IPv4_External_type
*ext_data
= NULL
;
413 struct TLV_IPv4_Internal_type
*int_data
= NULL
;
414 if (msg
->data_type
== EIGRP_TLV_IPv4_INT
)
416 int_data
= msg
->data
.ipv4_int_type
;
417 if (eigrp_metrics_is_same(&int_data
->metric
,&entry
->reported_metric
))
419 return 0; // No change
422 entry
->reported_distance
423 < eigrp_calculate_metrics(eigrp
, &int_data
->metric
) ? 1 :
424 entry
->reported_distance
425 > eigrp_calculate_metrics(eigrp
, &int_data
->metric
) ? 2 : 3; // Increase : Decrease : No change
426 entry
->reported_metric
= int_data
->metric
;
427 entry
->reported_distance
=
428 eigrp_calculate_metrics(eigrp
, &int_data
->metric
);
429 entry
->distance
= eigrp_calculate_total_metrics(eigrp
, entry
);
433 ext_data
= msg
->data
.ipv4_ext_data
;
434 if (eigrp_metrics_is_same (&ext_data
->metric
, &entry
->reported_metric
))
438 * Move to correct position in list according to new distance
440 listnode_delete(prefix
->entries
, entry
);
441 listnode_add_sort(prefix
->entries
, entry
);
447 eigrp_topology_update_all_node_flags(struct eigrp
*eigrp
)
449 struct list
*table
= eigrp
->topology_table
;
450 struct eigrp_prefix_entry
*data
;
451 struct listnode
*node
, *nnode
;
452 for (ALL_LIST_ELEMENTS(table
, node
, nnode
, data
))
454 eigrp_topology_update_node_flags(data
);
459 eigrp_topology_update_node_flags(struct eigrp_prefix_entry
*dest
)
461 struct listnode
*node
;
462 struct eigrp_neighbor_entry
*entry
;
463 struct eigrp
* eigrp
= eigrp_lookup();
465 for (ALL_LIST_ELEMENTS_RO(dest
->entries
, node
, entry
))
467 if ((entry
->distance
<= (u_int64_t
)(dest
->distance
*eigrp
->variance
)) &&
468 entry
->distance
!= EIGRP_MAX_METRIC
) // is successor
470 entry
->flags
|= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
;
471 entry
->flags
&= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG
;
473 else if (entry
->reported_distance
< dest
->fdistance
) // is feasible successor
475 entry
->flags
|= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG
;
476 entry
->flags
&= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
;
480 entry
->flags
&= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG
;
481 entry
->flags
&= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
;
487 eigrp_update_routing_table(struct eigrp_prefix_entry
* prefix
)
489 struct eigrp
*eigrp
= eigrp_lookup();
490 struct list
*successors
= eigrp_topology_get_successor_max(prefix
, eigrp
->max_paths
);
491 struct listnode
*node
;
492 struct eigrp_neighbor_entry
*entry
;
496 eigrp_zebra_route_add(prefix
->destination_ipv4
, successors
);
497 for (ALL_LIST_ELEMENTS_RO (successors
, node
, entry
))
498 entry
->flags
|= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG
;
500 list_delete(successors
);
504 eigrp_zebra_route_delete(prefix
->destination_ipv4
);
505 for (ALL_LIST_ELEMENTS_RO (prefix
->entries
, node
, entry
))
506 entry
->flags
&= ~EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG
;
511 eigrp_topology_neighbor_down(struct eigrp
*eigrp
, struct eigrp_neighbor
* nbr
)
513 struct listnode
*node1
, *node11
, *node2
, *node22
;
514 struct eigrp_prefix_entry
*prefix
;
515 struct eigrp_neighbor_entry
*entry
;
517 for (ALL_LIST_ELEMENTS(eigrp
->topology_table
, node1
, node11
, prefix
))
519 for (ALL_LIST_ELEMENTS(prefix
->entries
, node2
, node22
, entry
))
521 if (entry
->adv_router
== nbr
)
523 struct eigrp_fsm_action_message
*msg
;
524 msg
= XCALLOC(MTYPE_EIGRP_FSM_MSG
,
525 sizeof(struct eigrp_fsm_action_message
));
526 struct TLV_IPv4_Internal_type
* tlv
= eigrp_IPv4_InternalTLV_new();
527 tlv
->metric
.delay
= EIGRP_MAX_METRIC
;
528 msg
->packet_type
= EIGRP_OPC_UPDATE
;
530 msg
->data_type
= EIGRP_TLV_IPv4_INT
;
531 msg
->adv_router
= nbr
;
532 msg
->data
.ipv4_int_type
= tlv
;
534 msg
->prefix
= prefix
;
535 int event
= eigrp_get_fsm_event(msg
);
536 eigrp_fsm_event(msg
, event
);
541 eigrp_query_send_all(eigrp
);
542 eigrp_update_send_all(eigrp
,nbr
->ei
);
547 eigrp_update_topology_table_prefix(struct list
* table
, struct eigrp_prefix_entry
* prefix
)
549 struct listnode
*node1
, *node2
;
551 struct eigrp_neighbor_entry
*entry
;
552 for (ALL_LIST_ELEMENTS(prefix
->entries
, node1
, node2
, entry
))
554 if(entry
->distance
== EIGRP_MAX_METRIC
)
556 eigrp_neighbor_entry_delete(prefix
,entry
);
559 if(prefix
->distance
== EIGRP_MAX_METRIC
&& prefix
->nt
!= EIGRP_TOPOLOGY_TYPE_CONNECTED
)
561 eigrp_prefix_entry_delete(table
,prefix
);