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