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  */
eigrp_topology_new(void)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  */
eigrp_prefix_entry_new(void)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  */
eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry * entry1,struct eigrp_nexthop_entry * entry2)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 
eigrp_nexthop_entry_new(void)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  */
eigrp_topology_free(struct eigrp * eigrp,struct route_table * table)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  */
eigrp_prefix_entry_add(struct route_table * topology,struct eigrp_prefix_entry * pe)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 				__func__,
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  */
eigrp_nexthop_entry_add(struct eigrp * eigrp,struct eigrp_prefix_entry * node,struct eigrp_nexthop_entry * entry)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  */
eigrp_prefix_entry_delete(struct eigrp * eigrp,struct route_table * table,struct eigrp_prefix_entry * pe)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  */
eigrp_nexthop_entry_delete(struct eigrp * eigrp,struct eigrp_prefix_entry * node,struct eigrp_nexthop_entry * entry)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  */
eigrp_topology_delete_all(struct eigrp * eigrp,struct route_table * topology)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 *
eigrp_topology_table_lookup_ipv4(struct route_table * table,struct prefix * address)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  */
eigrp_topology_get_successor(struct eigrp_prefix_entry * table_node)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 *
eigrp_topology_get_successor_max(struct eigrp_prefix_entry * table_node,unsigned int maxpaths)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 *
eigrp_prefix_entry_lookup(struct list * entries,struct eigrp_neighbor * nbr)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 */
eigrp_neighbor_prefixes_lookup(struct eigrp * eigrp,struct eigrp_neighbor * nbr)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
eigrp_topology_update_distance(struct eigrp_fsm_action_message * msg)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 			 __func__);
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 
eigrp_topology_update_all_node_flags(struct eigrp * eigrp)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 
eigrp_topology_update_node_flags(struct eigrp * eigrp,struct eigrp_prefix_entry * dest)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 
eigrp_update_routing_table(struct eigrp * eigrp,struct eigrp_prefix_entry * prefix)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 
eigrp_topology_neighbor_down(struct eigrp * eigrp,struct eigrp_neighbor * nbr)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 			memset(&msg, 0, sizeof(msg));
512 			msg.metrics.delay = EIGRP_MAX_METRIC;
513 			msg.packet_type = EIGRP_OPC_UPDATE;
514 			msg.eigrp = eigrp;
515 			msg.data_type = EIGRP_INT;
516 			msg.adv_router = nbr;
517 			msg.entry = entry;
518 			msg.prefix = pe;
519 			eigrp_fsm_event(&msg);
520 		}
521 	}
522 
523 	eigrp_query_send_all(eigrp);
524 	eigrp_update_send_all(eigrp, nbr->ei);
525 }
526 
eigrp_update_topology_table_prefix(struct eigrp * eigrp,struct route_table * table,struct eigrp_prefix_entry * prefix)527 void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
528 					struct route_table *table,
529 					struct eigrp_prefix_entry *prefix)
530 {
531 	struct listnode *node1, *node2;
532 
533 	struct eigrp_nexthop_entry *entry;
534 	for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
535 		if (entry->distance == EIGRP_MAX_METRIC) {
536 			eigrp_nexthop_entry_delete(eigrp, prefix, entry);
537 		}
538 	}
539 	if (prefix->distance == EIGRP_MAX_METRIC
540 	    && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
541 		eigrp_prefix_entry_delete(eigrp, table, prefix);
542 	}
543 }
544