]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_topology.c
Merge branch 'master' into stylechecker
[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
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
54 static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *,
55 struct eigrp_nexthop_entry *);
56
57 /*
58 * Returns linkedlist used as topology table
59 * cmp - assigned function for comparing topology nodes
60 * del - assigned function executed before deleting topology node by list
61 * function
62 */
63 struct route_table *eigrp_topology_new()
64 {
65 return route_table_init();
66 }
67
68 /*
69 * Returns new created toplogy node
70 * cmp - assigned function for comparing topology entry
71 */
72 struct eigrp_prefix_entry *eigrp_prefix_entry_new()
73 {
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();
79 new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp;
80 new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
81 new->destination = NULL;
82
83 return new;
84 }
85
86 /*
87 * Topology entry comparison
88 */
89 static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
90 struct eigrp_nexthop_entry *entry2)
91 {
92 if (entry1->distance < entry2->distance)
93 return -1;
94 if (entry1->distance > entry2->distance)
95 return 1;
96
97 return 0;
98 }
99
100 /*
101 * Returns new topology entry
102 */
103
104 struct eigrp_nexthop_entry *eigrp_nexthop_entry_new()
105 {
106 struct eigrp_nexthop_entry *new;
107
108 new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY,
109 sizeof(struct eigrp_nexthop_entry));
110 new->reported_distance = EIGRP_MAX_METRIC;
111 new->distance = EIGRP_MAX_METRIC;
112
113 return new;
114 }
115
116 /*
117 * Freeing topology table list
118 */
119 void eigrp_topology_free(struct route_table *table)
120 {
121 route_table_finish(table);
122 }
123
124 /*
125 * Deleting all topology nodes in table
126 */
127 void eigrp_topology_cleanup(struct route_table *table)
128 {
129 eigrp_topology_delete_all(table);
130 }
131
132 /*
133 * Adding topology node to topology table
134 */
135 void eigrp_prefix_entry_add(struct route_table *topology,
136 struct eigrp_prefix_entry *pe)
137 {
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(
146 "%s: %s Should we have found this entry in the topo table?",
147 __PRETTY_FUNCTION__,
148 prefix2str(pe->destination, buf, sizeof(buf)));
149 }
150 }
151
152 rn->info = pe;
153 route_lock_node(rn);
154 }
155
156 /*
157 * Adding topology entry to topology node
158 */
159 void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
160 struct eigrp_nexthop_entry *entry)
161 {
162 struct list *l = list_new();
163
164 listnode_add(l, entry);
165
166 if (listnode_lookup(node->entries, entry) == NULL) {
167 listnode_add_sort(node->entries, entry);
168 entry->prefix = node;
169
170 eigrp_zebra_route_add(node->destination, l);
171 }
172
173 list_delete_and_null(&l);
174 }
175
176 /*
177 * Deleting topology node from topology table
178 */
179 void eigrp_prefix_entry_delete(struct route_table *table,
180 struct eigrp_prefix_entry *pe)
181 {
182 struct eigrp *eigrp = eigrp_lookup();
183 struct route_node *rn;
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 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);
203 }
204
205 /*
206 * Deleting topology entry from topology node
207 */
208 void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *node,
209 struct eigrp_nexthop_entry *entry)
210 {
211 if (listnode_lookup(node->entries, entry) != NULL) {
212 listnode_delete(node->entries, entry);
213 eigrp_zebra_route_delete(node->destination);
214 XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
215 }
216 }
217
218 /*
219 * Deleting all nodes from topology table
220 */
221 void eigrp_topology_delete_all(struct route_table *topology)
222 {
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 }
234 }
235
236 /*
237 * Return 0 if topology is not empty
238 * otherwise return 1
239 */
240 unsigned int eigrp_topology_table_isempty(struct list *topology)
241 {
242 if (topology->count)
243 return 1;
244 else
245 return 0;
246 }
247
248 struct eigrp_prefix_entry *
249 eigrp_topology_table_lookup_ipv4(struct route_table *table,
250 struct prefix *address)
251 {
252 struct eigrp_prefix_entry *pe;
253 struct route_node *rn;
254
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;
264 }
265
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 */
273 struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
274 {
275 struct list *successors = list_new();
276 struct eigrp_nexthop_entry *data;
277 struct listnode *node1, *node2;
278
279 for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
280 if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
281 listnode_add(successors, data);
282 }
283 }
284
285 /*
286 * If we have no successors return NULL
287 */
288 if (!successors->count) {
289 list_delete_and_null(&successors);
290 successors = NULL;
291 }
292
293 return successors;
294 }
295
296 struct list *
297 eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
298 unsigned int maxpaths)
299 {
300 struct list *successors = eigrp_topology_get_successor(table_node);
301
302 if (successors && successors->count > maxpaths) {
303 do {
304 struct listnode *node = listtail(successors);
305
306 list_delete_node(successors, node);
307
308 } while (successors->count > maxpaths);
309 }
310
311 return successors;
312 }
313
314 struct eigrp_nexthop_entry *
315 eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
316 {
317 struct eigrp_nexthop_entry *data;
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;
326 }
327
328 /* Lookup all prefixes from specified neighbor */
329 struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
330 struct eigrp_neighbor *nbr)
331 {
332 struct listnode *node2, *node22;
333 struct eigrp_nexthop_entry *entry;
334 struct eigrp_prefix_entry *pe;
335 struct route_node *rn;
336
337 /* create new empty list for prefixes storage */
338 struct list *prefixes = list_new();
339
340 /* iterate over all prefixes in topology table */
341 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
342 if (!rn->info)
343 continue;
344 pe = rn->info;
345 /* iterate over all neighbor entry in prefix */
346 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
347 /* if entry is from specified neighbor, add to list */
348 if (entry->adv_router == nbr) {
349 listnode_add(prefixes, pe);
350 }
351 }
352 }
353
354 /* return list of prefixes from specified neighbor */
355 return prefixes;
356 }
357
358 enum metric_change
359 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
360 {
361 struct eigrp *eigrp = msg->eigrp;
362 struct eigrp_prefix_entry *prefix = msg->prefix;
363 struct eigrp_nexthop_entry *entry = msg->entry;
364 enum metric_change change = METRIC_SAME;
365 u_int32_t new_reported_distance;
366
367 assert(entry);
368
369 switch (msg->data_type) {
370 case EIGRP_CONNECTED:
371 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED)
372 return change;
373
374 change = METRIC_DECREASE;
375 break;
376 case EIGRP_INT:
377 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) {
378 change = METRIC_INCREASE;
379 goto distance_done;
380 }
381 if (eigrp_metrics_is_same(msg->metrics,
382 entry->reported_metric)) {
383 return change; // No change
384 }
385
386 new_reported_distance =
387 eigrp_calculate_metrics(eigrp, msg->metrics);
388
389 if (entry->reported_distance < new_reported_distance) {
390 change = METRIC_INCREASE;
391 goto distance_done;
392 } else
393 change = METRIC_DECREASE;
394
395 entry->reported_metric = msg->metrics;
396 entry->reported_distance = new_reported_distance;
397 eigrp_calculate_metrics(eigrp, msg->metrics);
398 entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
399 break;
400 case EIGRP_EXT:
401 if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) {
402 if (eigrp_metrics_is_same(msg->metrics,
403 entry->reported_metric))
404 return change;
405 } else {
406 change = METRIC_INCREASE;
407 goto distance_done;
408 }
409 break;
410 default:
411 zlog_err("%s: Please implement handler", __PRETTY_FUNCTION__);
412 break;
413 }
414 distance_done:
415 /*
416 * Move to correct position in list according to new distance
417 */
418 listnode_delete(prefix->entries, entry);
419 listnode_add_sort(prefix->entries, entry);
420
421 return change;
422 }
423
424 void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
425 {
426 struct eigrp_prefix_entry *pe;
427 struct route_node *rn;
428
429 for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
430 pe = rn->info;
431
432 if (!pe)
433 continue;
434
435 eigrp_topology_update_node_flags(pe);
436 }
437 }
438
439 void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
440 {
441 struct listnode *node;
442 struct eigrp_nexthop_entry *entry;
443 struct eigrp *eigrp = eigrp_lookup();
444
445 for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
446 if (((uint64_t)entry->distance
447 <= (uint64_t)dest->distance * (uint64_t)eigrp->variance)
448 && entry->distance != EIGRP_MAX_METRIC) // is successor
449 {
450 entry->flags |= EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
451 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
452 } else if (entry->reported_distance
453 < dest->fdistance) // is feasible successor
454 {
455 entry->flags |= EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
456 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
457 } else {
458 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
459 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
460 }
461 }
462 }
463
464 void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
465 {
466 struct eigrp *eigrp = eigrp_lookup();
467 struct list *successors =
468 eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
469 struct listnode *node;
470 struct eigrp_nexthop_entry *entry;
471
472 if (successors) {
473 eigrp_zebra_route_add(prefix->destination, successors);
474 for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
475 entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
476
477 list_delete_and_null(&successors);
478 } else {
479 eigrp_zebra_route_delete(prefix->destination);
480 for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
481 entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
482 }
483 }
484
485 void eigrp_topology_neighbor_down(struct eigrp *eigrp,
486 struct eigrp_neighbor *nbr)
487 {
488 struct listnode *node2, *node22;
489 struct eigrp_prefix_entry *pe;
490 struct eigrp_nexthop_entry *entry;
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;
498
499 for (ALL_LIST_ELEMENTS(pe->entries, node2, node22, entry)) {
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;
511 msg.prefix = pe;
512 eigrp_fsm_event(&msg);
513 }
514 }
515
516 eigrp_query_send_all(eigrp);
517 eigrp_update_send_all(eigrp, nbr->ei);
518 }
519
520 void eigrp_update_topology_table_prefix(struct route_table *table,
521 struct eigrp_prefix_entry *prefix)
522 {
523 struct listnode *node1, *node2;
524
525 struct eigrp_nexthop_entry *entry;
526 for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
527 if (entry->distance == EIGRP_MAX_METRIC) {
528 eigrp_nexthop_entry_delete(prefix, entry);
529 }
530 }
531 if (prefix->distance == EIGRP_MAX_METRIC
532 && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
533 eigrp_prefix_entry_delete(table, prefix);
534 }
535 }