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