]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_topology.c
*: make consistent & update GPLv2 file headers
[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
f9e5c9ca
DS
54static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *);
55static void eigrp_prefix_entry_del(struct eigrp_prefix_entry *);
56static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *,
57 struct eigrp_neighbor_entry *);
7f57883e
DS
58
59/*
7f57883e
DS
60 * Returns linkedlist used as topology table
61 * cmp - assigned function for comparing topology nodes
62 * del - assigned function executed before deleting topology node by list function
63 */
64struct list *
65eigrp_topology_new()
66{
67 struct list* new = list_new();
68 new->cmp = (int
f9e5c9ca 69 (*)(void *, void *)) eigrp_prefix_entry_cmp;
7f57883e 70 new->del = (void
f9e5c9ca 71 (*)(void *)) eigrp_prefix_entry_del;
7f57883e
DS
72
73 return new;
74}
75
76/*
77 * Topology node comparison
78 */
79
80static int
81eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1,
f9e5c9ca 82 struct eigrp_prefix_entry *node2)
7f57883e
DS
83{
84 if (node1->af == AF_INET)
85 {
86 if (node2->af == AF_INET)
87 {
88 if (node1->destination_ipv4->prefix.s_addr
89 < node2->destination_ipv4->prefix.s_addr)
90 {
91 return -1; // if it belong above node2
92 }
93 else
94 {
95 if (node1->destination_ipv4->prefix.s_addr
96 > node2->destination_ipv4->prefix.s_addr)
97 {
98 return 1; //if it belongs under node2
99 }
100 else
101 {
102 return 0; // same value... ERROR...in case of adding same prefix again
103 }
104 }
105 }
106 else
107 {
108 return 1;
109 }
110 }
111 else
112 { // TODO check if the prefix dont exists
113 return 1; // add to end
114 }
115}
116
117/*
118 * Topology node delete
119 */
120
121static void
122eigrp_prefix_entry_del(struct eigrp_prefix_entry *node)
123{
124 list_delete_all_node(node->entries);
125 list_free(node->entries);
126}
127
128/*
129 * Returns new created toplogy node
130 * cmp - assigned function for comparing topology entry
131 */
7f57883e
DS
132struct eigrp_prefix_entry *
133eigrp_prefix_entry_new()
134{
135 struct eigrp_prefix_entry *new;
136 new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry));
137 new->entries = list_new();
138 new->rij = list_new();
9f56205c 139 new->entries->cmp = (int (*)(void *, void *))eigrp_neighbor_entry_cmp;
7f57883e
DS
140 new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
141 new->destination_ipv4 = NULL;
142 new->destination_ipv6 = NULL;
143
144 return new;
145}
146
147/*
148 * Topology entry comparison
149 */
7f57883e
DS
150static int
151eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1,
f9e5c9ca 152 struct eigrp_neighbor_entry *entry2)
7f57883e
DS
153{
154 if (entry1->distance < entry2->distance) // parameter used in list_add_sort ()
155 return -1; // actually set to sort by distance
156 if (entry1->distance > entry2->distance)
157 return 1;
158
159 return 0;
160}
161
162/*
163 * Returns new topology entry
164 */
165
166struct eigrp_neighbor_entry *
167eigrp_neighbor_entry_new()
168{
169 struct eigrp_neighbor_entry *new;
170
171 new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY,
f9e5c9ca 172 sizeof(struct eigrp_neighbor_entry));
7f57883e
DS
173 new->reported_distance = EIGRP_MAX_METRIC;
174 new->distance = EIGRP_MAX_METRIC;
175
176 return new;
177}
178
179/*
180 * Freeing topology table list
181 */
7f57883e
DS
182void
183eigrp_topology_free(struct list *list)
184{
185 list_free(list);
186}
187
188/*
189 * Deleting all topology nodes in table
190 */
7f57883e
DS
191void
192eigrp_topology_cleanup(struct list *topology)
193{
194 assert(topology);
195
196 eigrp_topology_delete_all(topology);
197}
198
199/*
200 * Adding topology node to topology table
201 */
7f57883e
DS
202void
203eigrp_prefix_entry_add(struct list *topology, struct eigrp_prefix_entry *node)
204{
205 if (listnode_lookup(topology, node) == NULL)
206 {
207 listnode_add_sort(topology, node);
208 }
209}
210
211/*
212 * Adding topology entry to topology node
213 */
7f57883e
DS
214void
215eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node,
f9e5c9ca 216 struct eigrp_neighbor_entry *entry)
7f57883e 217{
76220653
RW
218 struct list *l = list_new ();
219
63863c47
RW
220 listnode_add (l, entry);
221
76220653 222 if (listnode_lookup (node->entries, entry) == NULL)
7f57883e 223 {
76220653 224 listnode_add_sort (node->entries, entry);
7f57883e 225 entry->prefix = node;
63863c47
RW
226
227 eigrp_zebra_route_add (node->destination_ipv4, l);
7f57883e 228 }
76220653 229
76220653 230 list_delete (l);
7f57883e
DS
231}
232
233/*
234 * Deleting topology node from topology table
235 */
7f57883e
DS
236void
237eigrp_prefix_entry_delete(struct list *topology,
f9e5c9ca 238 struct eigrp_prefix_entry *node)
7f57883e 239{
703beb67
DS
240 struct eigrp *eigrp = eigrp_lookup ();
241
242 /*
243 * Emergency removal of the node from this list.
244 * Whatever it is.
245 */
76220653 246 listnode_delete (eigrp->topology_changes_internalIPV4, node);
703beb67 247
76220653 248 if (listnode_lookup (topology, node) != NULL)
7f57883e 249 {
76220653
RW
250 list_delete_all_node (node->entries);
251 list_free (node->entries);
252 list_free (node->rij);
253 listnode_delete (topology, node);
63863c47 254 eigrp_zebra_route_delete (node->destination_ipv4);
76220653 255 XFREE (MTYPE_EIGRP_PREFIX_ENTRY,node);
7f57883e
DS
256 }
257}
258
259/*
260 * Deleting topology entry from topology node
261 */
7f57883e
DS
262void
263eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node,
f9e5c9ca 264 struct eigrp_neighbor_entry *entry)
7f57883e
DS
265{
266 if (listnode_lookup(node->entries, entry) != NULL)
267 {
268 listnode_delete(node->entries, entry);
63863c47 269 eigrp_zebra_route_delete (node->destination_ipv4);
7f57883e
DS
270 XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY,entry);
271 }
272}
273
274/*
275 * Deleting all nodes from topology table
276 */
7f57883e
DS
277void
278eigrp_topology_delete_all(struct list *topology)
279{
280 list_delete_all_node(topology);
281}
282
283/*
284 * Return 0 if topology is not empty
285 * otherwise return 1
286 */
7f57883e
DS
287unsigned int
288eigrp_topology_table_isempty(struct list *topology)
289{
290 if (topology->count)
291 return 1;
292 else
293 return 0;
294}
295
296struct eigrp_prefix_entry *
297eigrp_topology_table_lookup_ipv4(struct list *topology_table,
f9e5c9ca 298 struct prefix_ipv4 * address)
7f57883e
DS
299{
300 struct eigrp_prefix_entry *data;
301 struct listnode *node;
302 for (ALL_LIST_ELEMENTS_RO(topology_table, node, data))
303 {
7f57883e
DS
304 if ((data->af == AF_INET)
305 && (data->destination_ipv4->prefix.s_addr == address->prefix.s_addr)
306 && (data->destination_ipv4->prefixlen == address->prefixlen))
307 return data;
308 }
309
310 return NULL;
311}
f6709c16 312
2118601d
DS
313/*
314 * For a future optimization, put the successor list into it's
315 * own separate list from the full list?
316 *
317 * That way we can clean up all the list_new and list_delete's
318 * that we are doing. DBS
319 */
7f57883e
DS
320struct list *
321eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
322{
323 struct list *successors = list_new();
7f57883e
DS
324 struct eigrp_neighbor_entry *data;
325 struct listnode *node1, *node2;
03f0bd35 326
7f57883e
DS
327 for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data))
328 {
329 if (data->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
330 {
331 listnode_add(successors, data);
332 }
333 }
334
f6709c16
DS
335 /*
336 * If we have no successors return NULL
337 */
338 if (!successors->count)
339 {
340 list_delete(successors);
341 successors = NULL;
342 }
343
7f57883e
DS
344 return successors;
345}
346
962251ae
DS
347struct list *
348eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
f9e5c9ca 349 unsigned int maxpaths)
962251ae
DS
350{
351 struct list *successors = eigrp_topology_get_successor(table_node);
f9e5c9ca 352
962251ae
DS
353 if (successors && successors->count > maxpaths)
354 {
355 do
f9e5c9ca
DS
356 {
357 struct listnode *node = listtail(successors);
962251ae 358
f9e5c9ca 359 list_delete_node(successors, node);
962251ae 360
f9e5c9ca 361 } while (successors->count > maxpaths);
962251ae
DS
362 }
363
364 return successors;
365}
366
7f57883e
DS
367struct eigrp_neighbor_entry *
368eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
369{
370 struct eigrp_neighbor_entry *data;
371 struct listnode *node, *nnode;
372 for (ALL_LIST_ELEMENTS(entries, node, nnode, data))
373 {
374 if (data->adv_router == nbr)
375 {
376 return data;
377 }
378 }
379
380 return NULL;
381}
382
383/* Lookup all prefixes from specified neighbor */
384struct list *
385eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, struct eigrp_neighbor *nbr)
386{
387 struct listnode *node1, *node11, *node2, *node22;
388 struct eigrp_prefix_entry *prefix;
389 struct eigrp_neighbor_entry *entry;
390
391 /* create new empty list for prefixes storage */
392 struct list *prefixes = list_new();
393
394 /* iterate over all prefixes in topology table */
395 for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix))
396 {
f9e5c9ca 397 /* iterate over all neighbor entry in prefix */
7f57883e
DS
398 for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry))
399 {
f9e5c9ca 400 /* if entry is from specified neighbor, add to list */
7f57883e
DS
401 if (entry->adv_router == nbr)
402 {
f9e5c9ca 403 listnode_add(prefixes, prefix);
7f57883e
DS
404 }
405 }
406 }
407
408 /* return list of prefixes from specified neighbor */
409 return prefixes;
410}
411
412int
413eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
414{
415 struct eigrp *eigrp = msg->eigrp;
416 struct eigrp_prefix_entry *prefix = msg->prefix;
417 struct eigrp_neighbor_entry *entry = msg->entry;
418 int change = 0;
419 assert(entry);
420
421 struct TLV_IPv4_External_type *ext_data = NULL;
422 struct TLV_IPv4_Internal_type *int_data = NULL;
423 if (msg->data_type == EIGRP_TLV_IPv4_INT)
424 {
425 int_data = msg->data.ipv4_int_type;
426 if (eigrp_metrics_is_same(&int_data->metric,&entry->reported_metric))
427 {
428 return 0; // No change
429 }
430 change =
f9e5c9ca
DS
431 entry->reported_distance
432 < eigrp_calculate_metrics(eigrp, &int_data->metric) ? 1 :
7f57883e 433 entry->reported_distance
f9e5c9ca 434 > eigrp_calculate_metrics(eigrp, &int_data->metric) ? 2 : 3; // Increase : Decrease : No change
7f57883e 435 entry->reported_metric = int_data->metric;
f9e5c9ca
DS
436 entry->reported_distance =
437 eigrp_calculate_metrics(eigrp, &int_data->metric);
7f57883e
DS
438 entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
439 }
440 else
441 {
442 ext_data = msg->data.ipv4_ext_data;
443 if (eigrp_metrics_is_same (&ext_data->metric, &entry->reported_metric))
f9e5c9ca 444 return 0;
7f57883e
DS
445 }
446 /*
447 * Move to correct position in list according to new distance
448 */
449 listnode_delete(prefix->entries, entry);
450 listnode_add_sort(prefix->entries, entry);
451
452 return change;
453}
454
455void
456eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
457{
458 struct list *table = eigrp->topology_table;
459 struct eigrp_prefix_entry *data;
460 struct listnode *node, *nnode;
461 for (ALL_LIST_ELEMENTS(table, node, nnode, data))
462 {
463 eigrp_topology_update_node_flags(data);
464 }
465}
466
467void
468eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
469{
470 struct listnode *node;
471 struct eigrp_neighbor_entry *entry;
472 struct eigrp * eigrp = eigrp_lookup();
473
474 for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry))
475 {
838cf8ab 476 if ((entry->distance <= (uint64_t)(dest->distance*eigrp->variance)) &&
f9e5c9ca 477 entry->distance != EIGRP_MAX_METRIC) // is successor
7f57883e
DS
478 {
479 entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
9f56205c 480 entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
7f57883e
DS
481 }
482 else if (entry->reported_distance < dest->fdistance) // is feasible successor
483 {
484 entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
9f56205c 485 entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
7f57883e
DS
486 }
487 else
488 {
9f56205c 489 entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
f9e5c9ca
DS
490 entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
491 }
7f57883e
DS
492 }
493}
494
495void
496eigrp_update_routing_table(struct eigrp_prefix_entry * prefix)
497{
962251ae
DS
498 struct eigrp *eigrp = eigrp_lookup();
499 struct list *successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
7f57883e
DS
500 struct listnode *node;
501 struct eigrp_neighbor_entry *entry;
502
2118601d 503 if (successors)
7f57883e 504 {
2118601d
DS
505 eigrp_zebra_route_add(prefix->destination_ipv4, successors);
506 for (ALL_LIST_ELEMENTS_RO (successors, node, entry))
f9e5c9ca 507 entry->flags |= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
2118601d
DS
508
509 list_delete(successors);
510 }
511 else
512 {
513 eigrp_zebra_route_delete(prefix->destination_ipv4);
514 for (ALL_LIST_ELEMENTS_RO (prefix->entries, node, entry))
f9e5c9ca 515 entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
7f57883e
DS
516 }
517}
518
519void
520eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor * nbr)
521{
522 struct listnode *node1, *node11, *node2, *node22;
523 struct eigrp_prefix_entry *prefix;
524 struct eigrp_neighbor_entry *entry;
525
526 for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix))
527 {
528 for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry))
529 {
530 if (entry->adv_router == nbr)
531 {
532 struct eigrp_fsm_action_message *msg;
533 msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
f9e5c9ca 534 sizeof(struct eigrp_fsm_action_message));
7f57883e
DS
535 struct TLV_IPv4_Internal_type * tlv = eigrp_IPv4_InternalTLV_new();
536 tlv->metric.delay = EIGRP_MAX_METRIC;
537 msg->packet_type = EIGRP_OPC_UPDATE;
538 msg->eigrp = eigrp;
539 msg->data_type = EIGRP_TLV_IPv4_INT;
540 msg->adv_router = nbr;
541 msg->data.ipv4_int_type = tlv;
542 msg->entry = entry;
543 msg->prefix = prefix;
544 int event = eigrp_get_fsm_event(msg);
545 eigrp_fsm_event(msg, event);
546 }
547 }
548 }
549
550 eigrp_query_send_all(eigrp);
551 eigrp_update_send_all(eigrp,nbr->ei);
552
553}
554
555void
556eigrp_update_topology_table_prefix(struct list * table, struct eigrp_prefix_entry * prefix)
557{
703beb67
DS
558 struct listnode *node1, *node2;
559
560 struct eigrp_neighbor_entry *entry;
561 for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry))
562 {
563 if(entry->distance == EIGRP_MAX_METRIC)
564 {
565 eigrp_neighbor_entry_delete(prefix,entry);
566 }
567 }
568 if(prefix->distance == EIGRP_MAX_METRIC && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED)
569 {
570 eigrp_prefix_entry_delete(table,prefix);
571 }
7f57883e 572}