]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_topology.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / eigrpd / eigrp_topology.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
7f57883e
DS
2/*
3 * EIGRP Topology Table.
4 * Copyright (C) 2013-2016
5 * Authors:
6 * Donnie Savage
7 * Jan Janovic
8 * Matej Perina
9 * Peter Orsag
10 * Peter Paluch
11 * Frantisek Gazo
12 * Tomas Hvorkovy
13 * Martin Kontsek
14 * Lukas Koribsky
7f57883e
DS
15 */
16
17#include <zebra.h>
18
19#include "prefix.h"
20#include "table.h"
21#include "memory.h"
22#include "log.h"
23#include "linklist.h"
24#include "vty.h"
6ae7ed45 25#include "lib_errors.h"
7f57883e 26
e9f1847e 27#include "eigrpd/eigrp_types.h"
7f57883e
DS
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"
e9f1847e 39#include "eigrpd/eigrp_metric.h"
7f57883e 40
b4216e2c
DL
41DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry");
42DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix");
43
dc4accdd
DS
44static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
45 struct eigrp_route_descriptor *rd2);
7f57883e
DS
46
47/*
7f57883e
DS
48 * Returns linkedlist used as topology table
49 * cmp - assigned function for comparing topology nodes
d62a17ae 50 * del - assigned function executed before deleting topology node by list
51 * function
7f57883e 52 */
4d762f26 53struct route_table *eigrp_topology_new(void)
7f57883e 54{
9ca66cc7 55 return route_table_init();
7f57883e
DS
56}
57
58/*
59 * Returns new created toplogy node
60 * cmp - assigned function for comparing topology entry
61 */
dc4accdd 62struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void)
7f57883e 63{
dc4accdd
DS
64 struct eigrp_prefix_descriptor *new;
65 new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
66 sizeof(struct eigrp_prefix_descriptor));
d62a17ae 67 new->entries = list_new();
68 new->rij = list_new();
dc4accdd 69 new->entries->cmp = (int (*)(void *, void *))eigrp_route_descriptor_cmp;
d62a17ae 70 new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
02b45998 71 new->destination = NULL;
d62a17ae 72
73 return new;
7f57883e
DS
74}
75
76/*
77 * Topology entry comparison
78 */
dc4accdd
DS
79static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *entry1,
80 struct eigrp_route_descriptor *entry2)
7f57883e 81{
02b45998
DS
82 if (entry1->distance < entry2->distance)
83 return -1;
d62a17ae 84 if (entry1->distance > entry2->distance)
85 return 1;
7f57883e 86
d62a17ae 87 return 0;
7f57883e
DS
88}
89
90/*
91 * Returns new topology entry
92 */
93
dc4accdd 94struct eigrp_route_descriptor *eigrp_route_descriptor_new(void)
7f57883e 95{
dc4accdd 96 struct eigrp_route_descriptor *new;
7f57883e 97
dc4accdd
DS
98 new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR,
99 sizeof(struct eigrp_route_descriptor));
d62a17ae 100 new->reported_distance = EIGRP_MAX_METRIC;
101 new->distance = EIGRP_MAX_METRIC;
7f57883e 102
d62a17ae 103 return new;
7f57883e
DS
104}
105
106/*
107 * Freeing topology table list
108 */
0da93ecf 109void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
7f57883e 110{
0da93ecf 111 eigrp_topology_delete_all(eigrp, table);
7eee7ef6 112 route_table_finish(table);
7f57883e
DS
113}
114
115/*
116 * Adding topology node to topology table
117 */
dc4accdd
DS
118void eigrp_prefix_descriptor_add(struct route_table *topology,
119 struct eigrp_prefix_descriptor *pe)
7f57883e 120{
9ca66cc7
DS
121 struct route_node *rn;
122
123 rn = route_node_get(topology, pe->destination);
124 if (rn->info) {
2dbe669b 125 if (IS_DEBUG_EIGRP_EVENT)
996c9314 126 zlog_debug(
2dbe669b
DA
127 "%s: %pFX Should we have found this entry in the topo table?",
128 __func__, pe->destination);
051da24e 129 route_unlock_node(rn);
d62a17ae 130 }
9ca66cc7
DS
131
132 rn->info = pe;
7f57883e
DS
133}
134
135/*
136 * Adding topology entry to topology node
137 */
dc4accdd
DS
138void eigrp_route_descriptor_add(struct eigrp *eigrp,
139 struct eigrp_prefix_descriptor *node,
140 struct eigrp_route_descriptor *entry)
7f57883e 141{
d62a17ae 142 struct list *l = list_new();
76220653 143
d62a17ae 144 listnode_add(l, entry);
63863c47 145
d62a17ae 146 if (listnode_lookup(node->entries, entry) == NULL) {
147 listnode_add_sort(node->entries, entry);
148 entry->prefix = node;
63863c47 149
0e64ed02
DS
150 eigrp_zebra_route_add(eigrp, node->destination,
151 l, node->fdistance);
d62a17ae 152 }
76220653 153
6a154c88 154 list_delete(&l);
7f57883e
DS
155}
156
157/*
158 * Deleting topology node from topology table
159 */
dc4accdd
DS
160void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
161 struct route_table *table,
162 struct eigrp_prefix_descriptor *pe)
7f57883e 163{
dc4accdd 164 struct eigrp_route_descriptor *ne;
7eee7ef6 165 struct listnode *node, *nnode;
9ca66cc7
DS
166 struct route_node *rn;
167
0bf75bd5 168 if (!eigrp)
169 return;
170
9ca66cc7
DS
171 rn = route_node_lookup(table, pe->destination);
172 if (!rn)
173 return;
d62a17ae 174
175 /*
176 * Emergency removal of the node from this list.
177 * Whatever it is.
178 */
9ca66cc7 179 listnode_delete(eigrp->topology_changes_internalIPV4, pe);
d62a17ae 180
7eee7ef6 181 for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
dc4accdd 182 eigrp_route_descriptor_delete(eigrp, pe, ne);
6a154c88
DL
183 list_delete(&pe->entries);
184 list_delete(&pe->rij);
0e64ed02 185 eigrp_zebra_route_delete(eigrp, pe->destination);
63265b5c 186 prefix_free(&pe->destination);
9ca66cc7
DS
187
188 rn->info = NULL;
996c9314
LB
189 route_unlock_node(rn); // Lookup above
190 route_unlock_node(rn); // Initial creation
dc4accdd 191 XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe);
7f57883e
DS
192}
193
194/*
195 * Deleting topology entry from topology node
196 */
dc4accdd
DS
197void eigrp_route_descriptor_delete(struct eigrp *eigrp,
198 struct eigrp_prefix_descriptor *node,
199 struct eigrp_route_descriptor *entry)
7f57883e 200{
d62a17ae 201 if (listnode_lookup(node->entries, entry) != NULL) {
202 listnode_delete(node->entries, entry);
0e64ed02 203 eigrp_zebra_route_delete(eigrp, node->destination);
dc4accdd 204 XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR, entry);
d62a17ae 205 }
7f57883e
DS
206}
207
208/*
209 * Deleting all nodes from topology table
210 */
0da93ecf
DS
211void eigrp_topology_delete_all(struct eigrp *eigrp,
212 struct route_table *topology)
7f57883e 213{
9ca66cc7 214 struct route_node *rn;
dc4accdd 215 struct eigrp_prefix_descriptor *pe;
9ca66cc7
DS
216
217 for (rn = route_top(topology); rn; rn = route_next(rn)) {
218 pe = rn->info;
219
220 if (!pe)
221 continue;
222
dc4accdd 223 eigrp_prefix_descriptor_delete(eigrp, topology, pe);
9ca66cc7 224 }
7f57883e
DS
225}
226
dc4accdd 227struct eigrp_prefix_descriptor *
9ca66cc7 228eigrp_topology_table_lookup_ipv4(struct route_table *table,
476a1469 229 struct prefix *address)
7f57883e 230{
dc4accdd 231 struct eigrp_prefix_descriptor *pe;
9ca66cc7 232 struct route_node *rn;
d62a17ae 233
9ca66cc7
DS
234 rn = route_node_lookup(table, address);
235 if (!rn)
236 return NULL;
237
238 pe = rn->info;
239
240 route_unlock_node(rn);
241
242 return pe;
7f57883e 243}
f6709c16 244
2118601d
DS
245/*
246 * For a future optimization, put the successor list into it's
247 * own separate list from the full list?
248 *
249 * That way we can clean up all the list_new and list_delete's
250 * that we are doing. DBS
251 */
dc4accdd
DS
252struct list *
253eigrp_topology_get_successor(struct eigrp_prefix_descriptor *table_node)
7f57883e 254{
d62a17ae 255 struct list *successors = list_new();
dc4accdd 256 struct eigrp_route_descriptor *data;
d62a17ae 257 struct listnode *node1, *node2;
258
259 for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
dc4accdd 260 if (data->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) {
d62a17ae 261 listnode_add(successors, data);
262 }
263 }
264
265 /*
266 * If we have no successors return NULL
267 */
268 if (!successors->count) {
6a154c88 269 list_delete(&successors);
d62a17ae 270 successors = NULL;
271 }
272
273 return successors;
7f57883e
DS
274}
275
962251ae 276struct list *
dc4accdd 277eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *table_node,
d62a17ae 278 unsigned int maxpaths)
962251ae 279{
d62a17ae 280 struct list *successors = eigrp_topology_get_successor(table_node);
962251ae 281
d62a17ae 282 if (successors && successors->count > maxpaths) {
283 do {
284 struct listnode *node = listtail(successors);
962251ae 285
d62a17ae 286 list_delete_node(successors, node);
962251ae 287
d62a17ae 288 } while (successors->count > maxpaths);
289 }
290
291 return successors;
962251ae
DS
292}
293
dc4accdd
DS
294struct eigrp_route_descriptor *
295eigrp_route_descriptor_lookup(struct list *entries, struct eigrp_neighbor *nbr)
7f57883e 296{
dc4accdd 297 struct eigrp_route_descriptor *data;
d62a17ae 298 struct listnode *node, *nnode;
299 for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) {
300 if (data->adv_router == nbr) {
301 return data;
302 }
303 }
304
305 return NULL;
7f57883e
DS
306}
307
308/* Lookup all prefixes from specified neighbor */
d62a17ae 309struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
310 struct eigrp_neighbor *nbr)
7f57883e 311{
9ca66cc7 312 struct listnode *node2, *node22;
dc4accdd
DS
313 struct eigrp_route_descriptor *entry;
314 struct eigrp_prefix_descriptor *pe;
9ca66cc7 315 struct route_node *rn;
d62a17ae 316
317 /* create new empty list for prefixes storage */
318 struct list *prefixes = list_new();
319
320 /* iterate over all prefixes in topology table */
9ca66cc7
DS
321 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
322 if (!rn->info)
323 continue;
324 pe = rn->info;
d62a17ae 325 /* iterate over all neighbor entry in prefix */
9ca66cc7 326 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
d62a17ae 327 /* if entry is from specified neighbor, add to list */
328 if (entry->adv_router == nbr) {
9ca66cc7 329 listnode_add(prefixes, pe);
d62a17ae 330 }
331 }
332 }
333
334 /* return list of prefixes from specified neighbor */
335 return prefixes;
7f57883e
DS
336}
337
996c9314
LB
338enum metric_change
339eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
7f57883e 340{
d62a17ae 341 struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
342 struct eigrp_prefix_descriptor *prefix = msg->prefix;
343 struct eigrp_route_descriptor *entry = msg->entry;
92948863 344 enum metric_change change = METRIC_SAME;
d7c0a89a 345 uint32_t new_reported_distance;
db6ec9ff 346
d62a17ae 347 assert(entry);
348
996c9314 349 switch (msg->data_type) {
7cfa4322 350 case EIGRP_CONNECTED:
db6ec9ff
DS
351 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED)
352 return change;
353
354 change = METRIC_DECREASE;
7cfa4322
DS
355 break;
356 case EIGRP_INT:
532e75e6
DS
357 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) {
358 change = METRIC_INCREASE;
359 goto distance_done;
360 }
db6ec9ff
DS
361 if (eigrp_metrics_is_same(msg->metrics,
362 entry->reported_metric)) {
363 return change; // No change
364 }
92948863 365
996c9314
LB
366 new_reported_distance =
367 eigrp_calculate_metrics(eigrp, msg->metrics);
92948863 368
532e75e6 369 if (entry->reported_distance < new_reported_distance) {
db6ec9ff 370 change = METRIC_INCREASE;
532e75e6
DS
371 goto distance_done;
372 } else
db6ec9ff 373 change = METRIC_DECREASE;
92948863 374
db6ec9ff
DS
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);
379 break;
7cfa4322 380 case EIGRP_EXT:
db6ec9ff
DS
381 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) {
382 if (eigrp_metrics_is_same(msg->metrics,
383 entry->reported_metric))
384 return change;
4a64eed5 385 } else {
db6ec9ff 386 change = METRIC_INCREASE;
532e75e6 387 goto distance_done;
4a64eed5
DS
388 }
389 break;
7cfa4322 390 default:
450971aa 391 flog_err(EC_LIB_DEVELOPMENT, "%s: Please implement handler",
15569c58 392 __func__);
7cfa4322 393 break;
d62a17ae 394 }
996c9314 395distance_done:
d62a17ae 396 /*
397 * Move to correct position in list according to new distance
398 */
399 listnode_delete(prefix->entries, entry);
400 listnode_add_sort(prefix->entries, entry);
401
402 return change;
7f57883e
DS
403}
404
d62a17ae 405void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
7f57883e 406{
dc4accdd 407 struct eigrp_prefix_descriptor *pe;
9ca66cc7
DS
408 struct route_node *rn;
409
0bf75bd5 410 if (!eigrp)
411 return;
412
9ca66cc7
DS
413 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
414 pe = rn->info;
415
416 if (!pe)
417 continue;
418
0da93ecf 419 eigrp_topology_update_node_flags(eigrp, pe);
d62a17ae 420 }
7f57883e
DS
421}
422
0da93ecf 423void eigrp_topology_update_node_flags(struct eigrp *eigrp,
dc4accdd 424 struct eigrp_prefix_descriptor *dest)
7f57883e 425{
d62a17ae 426 struct listnode *node;
dc4accdd 427 struct eigrp_route_descriptor *entry;
a2d7fdfe 428
d62a17ae 429 for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
53765081
PJ
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) {
436 // is successor
437 entry->flags |=
dc4accdd 438 EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
53765081 439 entry->flags &=
dc4accdd 440 ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
53765081
PJ
441 } else {
442 // is feasible successor only
443 entry->flags |=
dc4accdd 444 EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
53765081 445 entry->flags &=
dc4accdd 446 ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
53765081 447 }
d62a17ae 448 } else {
dc4accdd
DS
449 entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
450 entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
d62a17ae 451 }
452 }
7f57883e
DS
453}
454
0da93ecf 455void eigrp_update_routing_table(struct eigrp *eigrp,
dc4accdd 456 struct eigrp_prefix_descriptor *prefix)
7f57883e 457{
0bf75bd5 458 struct list *successors;
d62a17ae 459 struct listnode *node;
dc4accdd 460 struct eigrp_route_descriptor *entry;
d62a17ae 461
0bf75bd5 462 successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
463
d62a17ae 464 if (successors) {
0e64ed02 465 eigrp_zebra_route_add(eigrp, prefix->destination, successors,
0f9bc496 466 prefix->fdistance);
d62a17ae 467 for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
dc4accdd 468 entry->flags |= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
d62a17ae 469
6a154c88 470 list_delete(&successors);
d62a17ae 471 } else {
0e64ed02 472 eigrp_zebra_route_delete(eigrp, prefix->destination);
d62a17ae 473 for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
dc4accdd 474 entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
d62a17ae 475 }
7f57883e
DS
476}
477
d62a17ae 478void eigrp_topology_neighbor_down(struct eigrp *eigrp,
479 struct eigrp_neighbor *nbr)
7f57883e 480{
9ca66cc7 481 struct listnode *node2, *node22;
dc4accdd
DS
482 struct eigrp_prefix_descriptor *pe;
483 struct eigrp_route_descriptor *entry;
9ca66cc7
DS
484 struct route_node *rn;
485
486 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
487 pe = rn->info;
488
489 if (!pe)
490 continue;
d62a17ae 491
9ca66cc7 492 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
5ca6df78
DS
493 struct eigrp_fsm_action_message msg;
494
495 if (entry->adv_router != nbr)
496 continue;
497
de8b27a6 498 memset(&msg, 0, sizeof(msg));
5ca6df78
DS
499 msg.metrics.delay = EIGRP_MAX_METRIC;
500 msg.packet_type = EIGRP_OPC_UPDATE;
501 msg.eigrp = eigrp;
502 msg.data_type = EIGRP_INT;
503 msg.adv_router = nbr;
504 msg.entry = entry;
9ca66cc7 505 msg.prefix = pe;
5ca6df78 506 eigrp_fsm_event(&msg);
d62a17ae 507 }
508 }
509
510 eigrp_query_send_all(eigrp);
511 eigrp_update_send_all(eigrp, nbr->ei);
7f57883e
DS
512}
513
0da93ecf
DS
514void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
515 struct route_table *table,
dc4accdd 516 struct eigrp_prefix_descriptor *prefix)
7f57883e 517{
d62a17ae 518 struct listnode *node1, *node2;
519
dc4accdd 520 struct eigrp_route_descriptor *entry;
d62a17ae 521 for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
522 if (entry->distance == EIGRP_MAX_METRIC) {
dc4accdd 523 eigrp_route_descriptor_delete(eigrp, prefix, entry);
d62a17ae 524 }
525 }
526 if (prefix->distance == EIGRP_MAX_METRIC
527 && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
dc4accdd 528 eigrp_prefix_descriptor_delete(eigrp, table, prefix);
d62a17ae 529 }
7f57883e 530}