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