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