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