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