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