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