]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_topology.c
pimd: All paths have already derefed pim->global_scope.bsrp_table
[mirror_frr.git] / eigrpd / eigrp_topology.c
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 *
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
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 #include "lib_errors.h"
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
55 static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *,
56 struct eigrp_nexthop_entry *);
57
58 /*
59 * Returns linkedlist used as topology table
60 * cmp - assigned function for comparing topology nodes
61 * del - assigned function executed before deleting topology node by list
62 * function
63 */
64 struct route_table *eigrp_topology_new(void)
65 {
66 return route_table_init();
67 }
68
69 /*
70 * Returns new created toplogy node
71 * cmp - assigned function for comparing topology entry
72 */
73 struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
74 {
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();
80 new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp;
81 new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
82 new->destination = NULL;
83
84 return new;
85 }
86
87 /*
88 * Topology entry comparison
89 */
90 static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
91 struct eigrp_nexthop_entry *entry2)
92 {
93 if (entry1->distance < entry2->distance)
94 return -1;
95 if (entry1->distance > entry2->distance)
96 return 1;
97
98 return 0;
99 }
100
101 /*
102 * Returns new topology entry
103 */
104
105 struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void)
106 {
107 struct eigrp_nexthop_entry *new;
108
109 new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY,
110 sizeof(struct eigrp_nexthop_entry));
111 new->reported_distance = EIGRP_MAX_METRIC;
112 new->distance = EIGRP_MAX_METRIC;
113
114 return new;
115 }
116
117 /*
118 * Freeing topology table list
119 */
120 void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
121 {
122 eigrp_topology_delete_all(eigrp, table);
123 route_table_finish(table);
124 }
125
126 /*
127 * Adding topology node to topology table
128 */
129 void eigrp_prefix_entry_add(struct route_table *topology,
130 struct eigrp_prefix_entry *pe)
131 {
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
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)));
143 }
144 route_unlock_node(rn);
145 }
146
147 rn->info = pe;
148 }
149
150 /*
151 * Adding topology entry to topology node
152 */
153 void eigrp_nexthop_entry_add(struct eigrp *eigrp,
154 struct eigrp_prefix_entry *node,
155 struct eigrp_nexthop_entry *entry)
156 {
157 struct list *l = list_new();
158
159 listnode_add(l, entry);
160
161 if (listnode_lookup(node->entries, entry) == NULL) {
162 listnode_add_sort(node->entries, entry);
163 entry->prefix = node;
164
165 eigrp_zebra_route_add(eigrp, node->destination,
166 l, node->fdistance);
167 }
168
169 list_delete(&l);
170 }
171
172 /*
173 * Deleting topology node from topology table
174 */
175 void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
176 struct eigrp_prefix_entry *pe)
177 {
178 struct eigrp_nexthop_entry *ne;
179 struct listnode *node, *nnode;
180 struct route_node *rn;
181
182 if (!eigrp)
183 return;
184
185 rn = route_node_lookup(table, pe->destination);
186 if (!rn)
187 return;
188
189 /*
190 * Emergency removal of the node from this list.
191 * Whatever it is.
192 */
193 listnode_delete(eigrp->topology_changes_internalIPV4, pe);
194
195 for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
196 eigrp_nexthop_entry_delete(eigrp, pe, ne);
197 list_delete(&pe->entries);
198 list_delete(&pe->rij);
199 eigrp_zebra_route_delete(eigrp, pe->destination);
200 prefix_free(pe->destination);
201
202 rn->info = NULL;
203 route_unlock_node(rn); // Lookup above
204 route_unlock_node(rn); // Initial creation
205 XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe);
206 }
207
208 /*
209 * Deleting topology entry from topology node
210 */
211 void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
212 struct eigrp_prefix_entry *node,
213 struct eigrp_nexthop_entry *entry)
214 {
215 if (listnode_lookup(node->entries, entry) != NULL) {
216 listnode_delete(node->entries, entry);
217 eigrp_zebra_route_delete(eigrp, node->destination);
218 XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
219 }
220 }
221
222 /*
223 * Deleting all nodes from topology table
224 */
225 void eigrp_topology_delete_all(struct eigrp *eigrp,
226 struct route_table *topology)
227 {
228 struct route_node *rn;
229 struct eigrp_prefix_entry *pe;
230
231 for (rn = route_top(topology); rn; rn = route_next(rn)) {
232 pe = rn->info;
233
234 if (!pe)
235 continue;
236
237 eigrp_prefix_entry_delete(eigrp, topology, pe);
238 }
239 }
240
241 struct eigrp_prefix_entry *
242 eigrp_topology_table_lookup_ipv4(struct route_table *table,
243 struct prefix *address)
244 {
245 struct eigrp_prefix_entry *pe;
246 struct route_node *rn;
247
248 rn = route_node_lookup(table, address);
249 if (!rn)
250 return NULL;
251
252 pe = rn->info;
253
254 route_unlock_node(rn);
255
256 return pe;
257 }
258
259 /*
260 * For a future optimization, put the successor list into it's
261 * own separate list from the full list?
262 *
263 * That way we can clean up all the list_new and list_delete's
264 * that we are doing. DBS
265 */
266 struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
267 {
268 struct list *successors = list_new();
269 struct eigrp_nexthop_entry *data;
270 struct listnode *node1, *node2;
271
272 for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
273 if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
274 listnode_add(successors, data);
275 }
276 }
277
278 /*
279 * If we have no successors return NULL
280 */
281 if (!successors->count) {
282 list_delete(&successors);
283 successors = NULL;
284 }
285
286 return successors;
287 }
288
289 struct list *
290 eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
291 unsigned int maxpaths)
292 {
293 struct list *successors = eigrp_topology_get_successor(table_node);
294
295 if (successors && successors->count > maxpaths) {
296 do {
297 struct listnode *node = listtail(successors);
298
299 list_delete_node(successors, node);
300
301 } while (successors->count > maxpaths);
302 }
303
304 return successors;
305 }
306
307 struct eigrp_nexthop_entry *
308 eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
309 {
310 struct eigrp_nexthop_entry *data;
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;
319 }
320
321 /* Lookup all prefixes from specified neighbor */
322 struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
323 struct eigrp_neighbor *nbr)
324 {
325 struct listnode *node2, *node22;
326 struct eigrp_nexthop_entry *entry;
327 struct eigrp_prefix_entry *pe;
328 struct route_node *rn;
329
330 /* create new empty list for prefixes storage */
331 struct list *prefixes = list_new();
332
333 /* iterate over all prefixes in topology table */
334 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
335 if (!rn->info)
336 continue;
337 pe = rn->info;
338 /* iterate over all neighbor entry in prefix */
339 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
340 /* if entry is from specified neighbor, add to list */
341 if (entry->adv_router == nbr) {
342 listnode_add(prefixes, pe);
343 }
344 }
345 }
346
347 /* return list of prefixes from specified neighbor */
348 return prefixes;
349 }
350
351 enum metric_change
352 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
353 {
354 struct eigrp *eigrp = msg->eigrp;
355 struct eigrp_prefix_entry *prefix = msg->prefix;
356 struct eigrp_nexthop_entry *entry = msg->entry;
357 enum metric_change change = METRIC_SAME;
358 uint32_t new_reported_distance;
359
360 assert(entry);
361
362 switch (msg->data_type) {
363 case EIGRP_CONNECTED:
364 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED)
365 return change;
366
367 change = METRIC_DECREASE;
368 break;
369 case EIGRP_INT:
370 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) {
371 change = METRIC_INCREASE;
372 goto distance_done;
373 }
374 if (eigrp_metrics_is_same(msg->metrics,
375 entry->reported_metric)) {
376 return change; // No change
377 }
378
379 new_reported_distance =
380 eigrp_calculate_metrics(eigrp, msg->metrics);
381
382 if (entry->reported_distance < new_reported_distance) {
383 change = METRIC_INCREASE;
384 goto distance_done;
385 } else
386 change = METRIC_DECREASE;
387
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;
393 case EIGRP_EXT:
394 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) {
395 if (eigrp_metrics_is_same(msg->metrics,
396 entry->reported_metric))
397 return change;
398 } else {
399 change = METRIC_INCREASE;
400 goto distance_done;
401 }
402 break;
403 default:
404 flog_err(EC_LIB_DEVELOPMENT, "%s: Please implement handler",
405 __PRETTY_FUNCTION__);
406 break;
407 }
408 distance_done:
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;
416 }
417
418 void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
419 {
420 struct eigrp_prefix_entry *pe;
421 struct route_node *rn;
422
423 if (!eigrp)
424 return;
425
426 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
427 pe = rn->info;
428
429 if (!pe)
430 continue;
431
432 eigrp_topology_update_node_flags(eigrp, pe);
433 }
434 }
435
436 void eigrp_topology_update_node_flags(struct eigrp *eigrp,
437 struct eigrp_prefix_entry *dest)
438 {
439 struct listnode *node;
440 struct eigrp_nexthop_entry *entry;
441
442 for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
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 |=
451 EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
452 entry->flags &=
453 ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
454 } else {
455 // is feasible successor only
456 entry->flags |=
457 EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
458 entry->flags &=
459 ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
460 }
461 } else {
462 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
463 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
464 }
465 }
466 }
467
468 void eigrp_update_routing_table(struct eigrp *eigrp,
469 struct eigrp_prefix_entry *prefix)
470 {
471 struct list *successors;
472 struct listnode *node;
473 struct eigrp_nexthop_entry *entry;
474
475 successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
476
477 if (successors) {
478 eigrp_zebra_route_add(eigrp, prefix->destination, successors,
479 prefix->fdistance);
480 for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
481 entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
482
483 list_delete(&successors);
484 } else {
485 eigrp_zebra_route_delete(eigrp, prefix->destination);
486 for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
487 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
488 }
489 }
490
491 void eigrp_topology_neighbor_down(struct eigrp *eigrp,
492 struct eigrp_neighbor *nbr)
493 {
494 struct listnode *node2, *node22;
495 struct eigrp_prefix_entry *pe;
496 struct eigrp_nexthop_entry *entry;
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;
504
505 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
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;
517 msg.prefix = pe;
518 eigrp_fsm_event(&msg);
519 }
520 }
521
522 eigrp_query_send_all(eigrp);
523 eigrp_update_send_all(eigrp, nbr->ei);
524 }
525
526 void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
527 struct route_table *table,
528 struct eigrp_prefix_entry *prefix)
529 {
530 struct listnode *node1, *node2;
531
532 struct eigrp_nexthop_entry *entry;
533 for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
534 if (entry->distance == EIGRP_MAX_METRIC) {
535 eigrp_nexthop_entry_delete(eigrp, prefix, entry);
536 }
537 }
538 if (prefix->distance == EIGRP_MAX_METRIC
539 && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
540 eigrp_prefix_entry_delete(eigrp, table, prefix);
541 }
542 }