]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_topology.c
Merge pull request #3071 from donaldsharp/fix_vrf_name
[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 */
9ca66cc7 64struct route_table *eigrp_topology_new()
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 */
d62a17ae 73struct eigrp_prefix_entry *eigrp_prefix_entry_new()
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
255ab940 105struct eigrp_nexthop_entry *eigrp_nexthop_entry_new()
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 */
9ca66cc7 120void eigrp_topology_free(struct route_table *table)
7f57883e 121{
9ca66cc7 122 route_table_finish(table);
7f57883e
DS
123}
124
125/*
126 * Deleting all topology nodes in table
127 */
9ca66cc7 128void eigrp_topology_cleanup(struct route_table *table)
7f57883e 129{
9ca66cc7 130 eigrp_topology_delete_all(table);
7f57883e
DS
131}
132
133/*
134 * Adding topology node to topology table
135 */
9ca66cc7
DS
136void eigrp_prefix_entry_add(struct route_table *topology,
137 struct eigrp_prefix_entry *pe)
7f57883e 138{
9ca66cc7
DS
139 struct route_node *rn;
140
141 rn = route_node_get(topology, pe->destination);
142 if (rn->info) {
143 if (IS_DEBUG_EIGRP_EVENT) {
144 char buf[PREFIX_STRLEN];
145
996c9314
LB
146 zlog_debug(
147 "%s: %s Should we have found this entry in the topo table?",
148 __PRETTY_FUNCTION__,
149 prefix2str(pe->destination, buf, sizeof(buf)));
9ca66cc7 150 }
d62a17ae 151 }
9ca66cc7
DS
152
153 rn->info = pe;
154 route_lock_node(rn);
7f57883e
DS
155}
156
157/*
158 * Adding topology entry to topology node
159 */
255ab940 160void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
996c9314 161 struct eigrp_nexthop_entry *entry)
7f57883e 162{
d62a17ae 163 struct list *l = list_new();
76220653 164
d62a17ae 165 listnode_add(l, entry);
63863c47 166
d62a17ae 167 if (listnode_lookup(node->entries, entry) == NULL) {
168 listnode_add_sort(node->entries, entry);
169 entry->prefix = node;
63863c47 170
836aad7e 171 eigrp_zebra_route_add(node->destination, l);
d62a17ae 172 }
76220653 173
affe9e99 174 list_delete_and_null(&l);
7f57883e
DS
175}
176
177/*
178 * Deleting topology node from topology table
179 */
9ca66cc7
DS
180void eigrp_prefix_entry_delete(struct route_table *table,
181 struct eigrp_prefix_entry *pe)
7f57883e 182{
d62a17ae 183 struct eigrp *eigrp = eigrp_lookup();
9ca66cc7
DS
184 struct route_node *rn;
185
0bf75bd5 186 if (!eigrp)
187 return;
188
9ca66cc7
DS
189 rn = route_node_lookup(table, pe->destination);
190 if (!rn)
191 return;
d62a17ae 192
193 /*
194 * Emergency removal of the node from this list.
195 * Whatever it is.
196 */
9ca66cc7 197 listnode_delete(eigrp->topology_changes_internalIPV4, pe);
d62a17ae 198
9ca66cc7
DS
199 list_delete_and_null(&pe->entries);
200 list_delete_and_null(&pe->rij);
201 eigrp_zebra_route_delete(pe->destination);
202
203 rn->info = NULL;
996c9314
LB
204 route_unlock_node(rn); // Lookup above
205 route_unlock_node(rn); // Initial creation
9ca66cc7 206 XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe);
7f57883e
DS
207}
208
209/*
210 * Deleting topology entry from topology node
211 */
255ab940 212void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *node,
996c9314 213 struct eigrp_nexthop_entry *entry)
7f57883e 214{
d62a17ae 215 if (listnode_lookup(node->entries, entry) != NULL) {
216 listnode_delete(node->entries, entry);
836aad7e 217 eigrp_zebra_route_delete(node->destination);
255ab940 218 XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
d62a17ae 219 }
7f57883e
DS
220}
221
222/*
223 * Deleting all nodes from topology table
224 */
9ca66cc7 225void eigrp_topology_delete_all(struct route_table *topology)
7f57883e 226{
9ca66cc7
DS
227 struct route_node *rn;
228 struct eigrp_prefix_entry *pe;
229
230 for (rn = route_top(topology); rn; rn = route_next(rn)) {
231 pe = rn->info;
232
233 if (!pe)
234 continue;
235
236 eigrp_prefix_entry_delete(topology, pe);
237 }
7f57883e
DS
238}
239
240/*
241 * Return 0 if topology is not empty
242 * otherwise return 1
243 */
d62a17ae 244unsigned int eigrp_topology_table_isempty(struct list *topology)
7f57883e 245{
d62a17ae 246 if (topology->count)
247 return 1;
248 else
249 return 0;
7f57883e
DS
250}
251
252struct eigrp_prefix_entry *
9ca66cc7 253eigrp_topology_table_lookup_ipv4(struct route_table *table,
476a1469 254 struct prefix *address)
7f57883e 255{
9ca66cc7
DS
256 struct eigrp_prefix_entry *pe;
257 struct route_node *rn;
d62a17ae 258
9ca66cc7
DS
259 rn = route_node_lookup(table, address);
260 if (!rn)
261 return NULL;
262
263 pe = rn->info;
264
265 route_unlock_node(rn);
266
267 return pe;
7f57883e 268}
f6709c16 269
2118601d
DS
270/*
271 * For a future optimization, put the successor list into it's
272 * own separate list from the full list?
273 *
274 * That way we can clean up all the list_new and list_delete's
275 * that we are doing. DBS
276 */
d62a17ae 277struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
7f57883e 278{
d62a17ae 279 struct list *successors = list_new();
255ab940 280 struct eigrp_nexthop_entry *data;
d62a17ae 281 struct listnode *node1, *node2;
282
283 for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
255ab940 284 if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
d62a17ae 285 listnode_add(successors, data);
286 }
287 }
288
289 /*
290 * If we have no successors return NULL
291 */
292 if (!successors->count) {
affe9e99 293 list_delete_and_null(&successors);
d62a17ae 294 successors = NULL;
295 }
296
297 return successors;
7f57883e
DS
298}
299
962251ae
DS
300struct list *
301eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
d62a17ae 302 unsigned int maxpaths)
962251ae 303{
d62a17ae 304 struct list *successors = eigrp_topology_get_successor(table_node);
962251ae 305
d62a17ae 306 if (successors && successors->count > maxpaths) {
307 do {
308 struct listnode *node = listtail(successors);
962251ae 309
d62a17ae 310 list_delete_node(successors, node);
962251ae 311
d62a17ae 312 } while (successors->count > maxpaths);
313 }
314
315 return successors;
962251ae
DS
316}
317
255ab940 318struct eigrp_nexthop_entry *
7f57883e
DS
319eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
320{
255ab940 321 struct eigrp_nexthop_entry *data;
d62a17ae 322 struct listnode *node, *nnode;
323 for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) {
324 if (data->adv_router == nbr) {
325 return data;
326 }
327 }
328
329 return NULL;
7f57883e
DS
330}
331
332/* Lookup all prefixes from specified neighbor */
d62a17ae 333struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
334 struct eigrp_neighbor *nbr)
7f57883e 335{
9ca66cc7 336 struct listnode *node2, *node22;
255ab940 337 struct eigrp_nexthop_entry *entry;
9ca66cc7
DS
338 struct eigrp_prefix_entry *pe;
339 struct route_node *rn;
d62a17ae 340
341 /* create new empty list for prefixes storage */
342 struct list *prefixes = list_new();
343
344 /* iterate over all prefixes in topology table */
9ca66cc7
DS
345 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
346 if (!rn->info)
347 continue;
348 pe = rn->info;
d62a17ae 349 /* iterate over all neighbor entry in prefix */
9ca66cc7 350 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
d62a17ae 351 /* if entry is from specified neighbor, add to list */
352 if (entry->adv_router == nbr) {
9ca66cc7 353 listnode_add(prefixes, pe);
d62a17ae 354 }
355 }
356 }
357
358 /* return list of prefixes from specified neighbor */
359 return prefixes;
7f57883e
DS
360}
361
996c9314
LB
362enum metric_change
363eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
7f57883e 364{
d62a17ae 365 struct eigrp *eigrp = msg->eigrp;
366 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 367 struct eigrp_nexthop_entry *entry = msg->entry;
92948863 368 enum metric_change change = METRIC_SAME;
d7c0a89a 369 uint32_t new_reported_distance;
db6ec9ff 370
d62a17ae 371 assert(entry);
372
996c9314 373 switch (msg->data_type) {
7cfa4322 374 case EIGRP_CONNECTED:
db6ec9ff
DS
375 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED)
376 return change;
377
378 change = METRIC_DECREASE;
7cfa4322
DS
379 break;
380 case EIGRP_INT:
532e75e6
DS
381 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) {
382 change = METRIC_INCREASE;
383 goto distance_done;
384 }
db6ec9ff
DS
385 if (eigrp_metrics_is_same(msg->metrics,
386 entry->reported_metric)) {
387 return change; // No change
388 }
92948863 389
996c9314
LB
390 new_reported_distance =
391 eigrp_calculate_metrics(eigrp, msg->metrics);
92948863 392
532e75e6 393 if (entry->reported_distance < new_reported_distance) {
db6ec9ff 394 change = METRIC_INCREASE;
532e75e6
DS
395 goto distance_done;
396 } else
db6ec9ff 397 change = METRIC_DECREASE;
92948863 398
db6ec9ff
DS
399 entry->reported_metric = msg->metrics;
400 entry->reported_distance = new_reported_distance;
401 eigrp_calculate_metrics(eigrp, msg->metrics);
402 entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
403 break;
7cfa4322 404 case EIGRP_EXT:
db6ec9ff
DS
405 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) {
406 if (eigrp_metrics_is_same(msg->metrics,
407 entry->reported_metric))
408 return change;
4a64eed5 409 } else {
db6ec9ff 410 change = METRIC_INCREASE;
532e75e6 411 goto distance_done;
4a64eed5
DS
412 }
413 break;
7cfa4322 414 default:
450971aa 415 flog_err(EC_LIB_DEVELOPMENT, "%s: Please implement handler",
1c50c1c0 416 __PRETTY_FUNCTION__);
7cfa4322 417 break;
d62a17ae 418 }
996c9314 419distance_done:
d62a17ae 420 /*
421 * Move to correct position in list according to new distance
422 */
423 listnode_delete(prefix->entries, entry);
424 listnode_add_sort(prefix->entries, entry);
425
426 return change;
7f57883e
DS
427}
428
d62a17ae 429void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
7f57883e 430{
9ca66cc7
DS
431 struct eigrp_prefix_entry *pe;
432 struct route_node *rn;
433
0bf75bd5 434 if (!eigrp)
435 return;
436
9ca66cc7
DS
437 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
438 pe = rn->info;
439
440 if (!pe)
441 continue;
442
443 eigrp_topology_update_node_flags(pe);
d62a17ae 444 }
7f57883e
DS
445}
446
d62a17ae 447void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
7f57883e 448{
d62a17ae 449 struct listnode *node;
255ab940 450 struct eigrp_nexthop_entry *entry;
d62a17ae 451 struct eigrp *eigrp = eigrp_lookup();
452
a2d7fdfe 453 assert(eigrp);
454
d62a17ae 455 for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
53765081
PJ
456 if (entry->reported_distance < dest->fdistance) {
457 // is feasible successor, can be successor
458 if (((uint64_t)entry->distance
459 <= (uint64_t)dest->distance
460 * (uint64_t)eigrp->variance)
461 && entry->distance != EIGRP_MAX_METRIC) {
462 // is successor
463 entry->flags |=
464 EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
465 entry->flags &=
466 ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
467 } else {
468 // is feasible successor only
469 entry->flags |=
470 EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
471 entry->flags &=
472 ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
473 }
d62a17ae 474 } else {
255ab940
DS
475 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
476 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
d62a17ae 477 }
478 }
7f57883e
DS
479}
480
d62a17ae 481void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
7f57883e 482{
d62a17ae 483 struct eigrp *eigrp = eigrp_lookup();
0bf75bd5 484 struct list *successors;
d62a17ae 485 struct listnode *node;
255ab940 486 struct eigrp_nexthop_entry *entry;
d62a17ae 487
0bf75bd5 488 if (!eigrp)
489 return;
490
491 successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
492
d62a17ae 493 if (successors) {
996c9314 494 eigrp_zebra_route_add(prefix->destination, successors);
d62a17ae 495 for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
255ab940 496 entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
d62a17ae 497
affe9e99 498 list_delete_and_null(&successors);
d62a17ae 499 } else {
836aad7e 500 eigrp_zebra_route_delete(prefix->destination);
d62a17ae 501 for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
255ab940 502 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
d62a17ae 503 }
7f57883e
DS
504}
505
d62a17ae 506void eigrp_topology_neighbor_down(struct eigrp *eigrp,
507 struct eigrp_neighbor *nbr)
7f57883e 508{
9ca66cc7
DS
509 struct listnode *node2, *node22;
510 struct eigrp_prefix_entry *pe;
255ab940 511 struct eigrp_nexthop_entry *entry;
9ca66cc7
DS
512 struct route_node *rn;
513
514 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
515 pe = rn->info;
516
517 if (!pe)
518 continue;
d62a17ae 519
9ca66cc7 520 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
5ca6df78
DS
521 struct eigrp_fsm_action_message msg;
522
523 if (entry->adv_router != nbr)
524 continue;
525
526 msg.metrics.delay = EIGRP_MAX_METRIC;
527 msg.packet_type = EIGRP_OPC_UPDATE;
528 msg.eigrp = eigrp;
529 msg.data_type = EIGRP_INT;
530 msg.adv_router = nbr;
531 msg.entry = entry;
9ca66cc7 532 msg.prefix = pe;
5ca6df78 533 eigrp_fsm_event(&msg);
d62a17ae 534 }
535 }
536
537 eigrp_query_send_all(eigrp);
538 eigrp_update_send_all(eigrp, nbr->ei);
7f57883e
DS
539}
540
9ca66cc7 541void eigrp_update_topology_table_prefix(struct route_table *table,
d62a17ae 542 struct eigrp_prefix_entry *prefix)
7f57883e 543{
d62a17ae 544 struct listnode *node1, *node2;
545
255ab940 546 struct eigrp_nexthop_entry *entry;
d62a17ae 547 for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
548 if (entry->distance == EIGRP_MAX_METRIC) {
255ab940 549 eigrp_nexthop_entry_delete(prefix, entry);
d62a17ae 550 }
551 }
552 if (prefix->distance == EIGRP_MAX_METRIC
553 && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
554 eigrp_prefix_entry_delete(table, prefix);
555 }
7f57883e 556}