]>
Commit | Line | Data |
---|---|---|
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 |
54 | static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *); |
55 | static void eigrp_prefix_entry_del(struct eigrp_prefix_entry *); | |
56 | static 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 | */ | |
64 | struct list * | |
65 | eigrp_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 | ||
80 | static int | |
81 | eigrp_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 | ||
121 | static void | |
122 | eigrp_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 |
132 | struct eigrp_prefix_entry * |
133 | eigrp_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 |
150 | static int |
151 | eigrp_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 | ||
166 | struct eigrp_neighbor_entry * | |
167 | eigrp_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 |
182 | void |
183 | eigrp_topology_free(struct list *list) | |
184 | { | |
185 | list_free(list); | |
186 | } | |
187 | ||
188 | /* | |
189 | * Deleting all topology nodes in table | |
190 | */ | |
7f57883e DS |
191 | void |
192 | eigrp_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 |
202 | void |
203 | eigrp_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 |
214 | void |
215 | eigrp_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 |
236 | void |
237 | eigrp_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 |
262 | void |
263 | eigrp_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 |
277 | void |
278 | eigrp_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 |
287 | unsigned int |
288 | eigrp_topology_table_isempty(struct list *topology) | |
289 | { | |
290 | if (topology->count) | |
291 | return 1; | |
292 | else | |
293 | return 0; | |
294 | } | |
295 | ||
296 | struct eigrp_prefix_entry * | |
297 | eigrp_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 |
320 | struct list * |
321 | eigrp_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 |
347 | struct list * |
348 | eigrp_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 |
367 | struct eigrp_neighbor_entry * |
368 | eigrp_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 */ | |
384 | struct list * | |
385 | eigrp_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 | ||
412 | int | |
413 | eigrp_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 | ||
455 | void | |
456 | eigrp_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 | ||
467 | void | |
468 | eigrp_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 | ||
495 | void | |
496 | eigrp_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 | ||
519 | void | |
520 | eigrp_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 | ||
555 | void | |
556 | eigrp_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 | } |