]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_route.c
bgpd: Add hidden `next-hop-self all` for all address families
[mirror_frr.git] / isisd / isis_route.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_route.c
3 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 4 * Tampere University of Technology
eb5d44eb 5 * Institute of Communications Engineering
6 *
7 * based on ../ospf6d/ospf6_route.[ch]
8 * by Yasuhiro Ohara
9 *
d62a17ae 10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public Licenseas published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
eb5d44eb 13 * any later version.
14 *
d62a17ae 15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
eb5d44eb 18 * more details.
896014f4
DL
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
eb5d44eb 23 */
24
eb5d44eb 25#include <zebra.h>
eb5d44eb 26
27#include "thread.h"
28#include "linklist.h"
29#include "vty.h"
30#include "log.h"
31#include "memory.h"
32#include "prefix.h"
33#include "hash.h"
34#include "if.h"
35#include "table.h"
321c1bbb 36#include "srcdest_table.h"
eb5d44eb 37
38#include "isis_constants.h"
39#include "isis_common.h"
3f045a08 40#include "isis_flags.h"
eb5d44eb 41#include "isisd.h"
42#include "isis_misc.h"
43#include "isis_adjacency.h"
44#include "isis_circuit.h"
eb5d44eb 45#include "isis_pdu.h"
46#include "isis_lsp.h"
47#include "isis_spf.h"
48#include "isis_route.h"
49#include "isis_zebra.h"
50
d62a17ae 51static struct isis_nexthop *isis_nexthop_create(struct in_addr *ip,
52 ifindex_t ifindex)
eb5d44eb 53{
d62a17ae 54 struct listnode *node;
55 struct isis_nexthop *nexthop;
f390d2c7 56
d62a17ae 57 for (ALL_LIST_ELEMENTS_RO(isis->nexthops, node, nexthop)) {
58 if (nexthop->ifindex != ifindex)
59 continue;
60 if (ip && memcmp(&nexthop->ip, ip, sizeof(struct in_addr)) != 0)
61 continue;
f390d2c7 62
d62a17ae 63 nexthop->lock++;
64 return nexthop;
65 }
f390d2c7 66
d62a17ae 67 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
f390d2c7 68
d62a17ae 69 nexthop->ifindex = ifindex;
70 memcpy(&nexthop->ip, ip, sizeof(struct in_addr));
71 listnode_add(isis->nexthops, nexthop);
72 nexthop->lock++;
eb5d44eb 73
d62a17ae 74 return nexthop;
eb5d44eb 75}
76
d62a17ae 77static void isis_nexthop_delete(struct isis_nexthop *nexthop)
eb5d44eb 78{
d62a17ae 79 nexthop->lock--;
80 if (nexthop->lock == 0) {
81 listnode_delete(isis->nexthops, nexthop);
82 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
83 }
84
85 return;
eb5d44eb 86}
87
d62a17ae 88static int nexthoplookup(struct list *nexthops, struct in_addr *ip,
89 ifindex_t ifindex)
eb5d44eb 90{
d62a17ae 91 struct listnode *node;
92 struct isis_nexthop *nh;
eb5d44eb 93
d62a17ae 94 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
95 if (!(memcmp(ip, &nh->ip, sizeof(struct in_addr)))
96 && ifindex == nh->ifindex)
97 return 1;
98 }
eb5d44eb 99
d62a17ae 100 return 0;
eb5d44eb 101}
102
d62a17ae 103static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6,
104 ifindex_t ifindex)
eb5d44eb 105{
d62a17ae 106 struct isis_nexthop6 *nexthop6;
f390d2c7 107
d62a17ae 108 nexthop6 = XCALLOC(MTYPE_ISIS_NEXTHOP6, sizeof(struct isis_nexthop6));
f390d2c7 109
d62a17ae 110 nexthop6->ifindex = ifindex;
111 memcpy(&nexthop6->ip6, ip6, sizeof(struct in6_addr));
112 nexthop6->lock++;
eb5d44eb 113
d62a17ae 114 return nexthop6;
eb5d44eb 115}
116
d62a17ae 117static struct isis_nexthop6 *isis_nexthop6_create(struct in6_addr *ip6,
118 ifindex_t ifindex)
eb5d44eb 119{
d62a17ae 120 struct listnode *node;
121 struct isis_nexthop6 *nexthop6;
122
123 for (ALL_LIST_ELEMENTS_RO(isis->nexthops6, node, nexthop6)) {
124 if (nexthop6->ifindex != ifindex)
125 continue;
126 if (ip6
127 && memcmp(&nexthop6->ip6, ip6, sizeof(struct in6_addr))
128 != 0)
129 continue;
130
131 nexthop6->lock++;
132 return nexthop6;
133 }
f390d2c7 134
d62a17ae 135 nexthop6 = isis_nexthop6_new(ip6, ifindex);
eb5d44eb 136
d62a17ae 137 return nexthop6;
eb5d44eb 138}
139
d62a17ae 140static void isis_nexthop6_delete(struct isis_nexthop6 *nexthop6)
eb5d44eb 141{
142
d62a17ae 143 nexthop6->lock--;
144 if (nexthop6->lock == 0) {
145 listnode_delete(isis->nexthops6, nexthop6);
146 XFREE(MTYPE_ISIS_NEXTHOP6, nexthop6);
147 }
f390d2c7 148
d62a17ae 149 return;
eb5d44eb 150}
151
d62a17ae 152static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6,
153 ifindex_t ifindex)
eb5d44eb 154{
d62a17ae 155 struct listnode *node;
156 struct isis_nexthop6 *nh6;
eb5d44eb 157
d62a17ae 158 for (ALL_LIST_ELEMENTS_RO(nexthops6, node, nh6)) {
159 if (!(memcmp(ip6, &nh6->ip6, sizeof(struct in6_addr)))
160 && ifindex == nh6->ifindex)
161 return 1;
162 }
eb5d44eb 163
d62a17ae 164 return 0;
eb5d44eb 165}
166
d62a17ae 167static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
eb5d44eb 168{
d62a17ae 169 struct isis_nexthop *nh;
d62a17ae 170
0c1bd758
CF
171 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
172 struct in_addr *ipv4_addr = &adj->ipv4_addresses[i];
d62a17ae 173 if (!nexthoplookup(nexthops, ipv4_addr,
174 adj->circuit->interface->ifindex)) {
175 nh = isis_nexthop_create(
176 ipv4_addr, adj->circuit->interface->ifindex);
177 nh->router_address = adj->router_address;
178 listnode_add(nexthops, nh);
74361f41 179 return;
d62a17ae 180 }
f390d2c7 181 }
eb5d44eb 182}
183
d62a17ae 184static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
eb5d44eb 185{
d62a17ae 186 struct isis_nexthop6 *nh6;
187
0c1bd758
CF
188 for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
189 struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i];
d62a17ae 190 if (!nexthop6lookup(nexthops6, ipv6_addr,
191 adj->circuit->interface->ifindex)) {
192 nh6 = isis_nexthop6_create(
193 ipv6_addr, adj->circuit->interface->ifindex);
194 nh6->router_address6 = adj->router_address6;
195 listnode_add(nexthops6, nh6);
74361f41 196 return;
d62a17ae 197 }
f390d2c7 198 }
eb5d44eb 199}
eb5d44eb 200
d62a17ae 201static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
321c1bbb 202 struct prefix_ipv6 *src_p,
d62a17ae 203 uint32_t cost,
204 uint32_t depth,
205 struct list *adjacencies)
eb5d44eb 206{
d62a17ae 207 struct isis_route_info *rinfo;
208 struct isis_adjacency *adj;
209 struct listnode *node;
210
211 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
212
213 if (prefix->family == AF_INET) {
214 rinfo->nexthops = list_new();
215 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
216 /* check for force resync this route */
217 if (CHECK_FLAG(adj->circuit->flags,
218 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
219 SET_FLAG(rinfo->flag,
220 ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
221 /* update neighbor router address */
222 if (depth == 2 && prefix->prefixlen == 32)
223 adj->router_address = prefix->u.prefix4;
224 adjinfo2nexthop(rinfo->nexthops, adj);
225 }
226 }
227 if (prefix->family == AF_INET6) {
228 rinfo->nexthops6 = list_new();
229 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
230 /* check for force resync this route */
231 if (CHECK_FLAG(adj->circuit->flags,
232 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
233 SET_FLAG(rinfo->flag,
234 ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
235 /* update neighbor router address */
321c1bbb
CF
236 if (depth == 2 && prefix->prefixlen == 128
237 && (!src_p || !src_p->prefixlen)) {
d62a17ae 238 adj->router_address6 = prefix->u.prefix6;
321c1bbb 239 }
d62a17ae 240 adjinfo2nexthop6(rinfo->nexthops6, adj);
241 }
242 }
243
244 rinfo->cost = cost;
245 rinfo->depth = depth;
246
247 return rinfo;
eb5d44eb 248}
249
d62a17ae 250static void isis_route_info_delete(struct isis_route_info *route_info)
eb5d44eb 251{
d62a17ae 252 if (route_info->nexthops) {
253 route_info->nexthops->del =
254 (void (*)(void *))isis_nexthop_delete;
6a154c88 255 list_delete(&route_info->nexthops);
d62a17ae 256 }
257
258 if (route_info->nexthops6) {
259 route_info->nexthops6->del =
260 (void (*)(void *))isis_nexthop6_delete;
6a154c88 261 list_delete(&route_info->nexthops6);
d62a17ae 262 }
263
264 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
eb5d44eb 265}
266
d62a17ae 267static int isis_route_info_same_attrib(struct isis_route_info *new,
268 struct isis_route_info *old)
eb5d44eb 269{
d62a17ae 270 if (new->cost != old->cost)
271 return 0;
272 if (new->depth != old->depth)
273 return 0;
f390d2c7 274
d62a17ae 275 return 1;
eb5d44eb 276}
277
d62a17ae 278static int isis_route_info_same(struct isis_route_info *new,
d7c0a89a 279 struct isis_route_info *old, uint8_t family)
eb5d44eb 280{
d62a17ae 281 struct listnode *node;
282 struct isis_nexthop *nexthop;
283 struct isis_nexthop6 *nexthop6;
284
285 if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
286 return 0;
287
288 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
289 return 0;
290
291 if (!isis_route_info_same_attrib(new, old))
292 return 0;
293
294 if (family == AF_INET) {
295 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
296 if (nexthoplookup(old->nexthops, &nexthop->ip,
297 nexthop->ifindex)
298 == 0)
299 return 0;
300
301 for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
302 if (nexthoplookup(new->nexthops, &nexthop->ip,
303 nexthop->ifindex)
304 == 0)
305 return 0;
306 } else if (family == AF_INET6) {
307 for (ALL_LIST_ELEMENTS_RO(new->nexthops6, node, nexthop6))
308 if (nexthop6lookup(old->nexthops6, &nexthop6->ip6,
309 nexthop6->ifindex)
310 == 0)
311 return 0;
312
313 for (ALL_LIST_ELEMENTS_RO(old->nexthops6, node, nexthop6))
314 if (nexthop6lookup(new->nexthops6, &nexthop6->ip6,
315 nexthop6->ifindex)
316 == 0)
317 return 0;
318 }
319
320 return 1;
eb5d44eb 321}
322
321c1bbb
CF
323struct isis_route_info *isis_route_create(struct prefix *prefix,
324 struct prefix_ipv6 *src_p,
325 uint32_t cost,
d7c0a89a 326 uint32_t depth,
d62a17ae 327 struct list *adjacencies,
3dace42d
CF
328 struct isis_area *area,
329 struct route_table *table)
eb5d44eb 330{
d62a17ae 331 struct route_node *route_node;
332 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
333 char buff[PREFIX2STR_BUFFER];
d7c0a89a 334 uint8_t family;
d62a17ae 335
336 family = prefix->family;
337 /* for debugs */
338 prefix2str(prefix, buff, sizeof(buff));
339
3dace42d 340 if (!table)
d62a17ae 341 return NULL;
3dace42d 342
321c1bbb
CF
343 rinfo_new = isis_route_info_new(prefix, src_p, cost,
344 depth, adjacencies);
345 route_node = srcdest_rnode_get(table, prefix, src_p);
d62a17ae 346
347 rinfo_old = route_node->info;
348 if (!rinfo_old) {
349 if (isis->debugs & DEBUG_RTE_EVENTS)
350 zlog_debug("ISIS-Rte (%s) route created: %s",
351 area->area_tag, buff);
352 route_info = rinfo_new;
353 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
354 } else {
bcd9fd50 355 route_unlock_node(route_node);
d62a17ae 356 if (isis->debugs & DEBUG_RTE_EVENTS)
357 zlog_debug("ISIS-Rte (%s) route already exists: %s",
358 area->area_tag, buff);
359 if (isis_route_info_same(rinfo_new, rinfo_old, family)) {
360 if (isis->debugs & DEBUG_RTE_EVENTS)
361 zlog_debug("ISIS-Rte (%s) route unchanged: %s",
362 area->area_tag, buff);
363 isis_route_info_delete(rinfo_new);
364 route_info = rinfo_old;
365 } else {
366 if (isis->debugs & DEBUG_RTE_EVENTS)
367 zlog_debug("ISIS-Rte (%s) route changed: %s",
368 area->area_tag, buff);
369 isis_route_info_delete(rinfo_old);
370 route_info = rinfo_new;
371 UNSET_FLAG(route_info->flag,
372 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
373 }
374 }
375
376 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
377 route_node->info = route_info;
378
379 return route_info;
eb5d44eb 380}
381
bcd9fd50 382static void isis_route_delete(struct route_node *rode,
321c1bbb 383 struct route_table *table)
eb5d44eb 384{
d62a17ae 385 struct isis_route_info *rinfo;
321c1bbb 386 char buff[SRCDEST2STR_BUFFER];
bcd9fd50
CF
387 struct prefix *prefix;
388 struct prefix_ipv6 *src_p;
d62a17ae 389
390 /* for log */
bcd9fd50 391 srcdest_rnode2str(rode, buff, sizeof(buff));
d62a17ae 392
bcd9fd50
CF
393 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
394 (const struct prefix **)&src_p);
d62a17ae 395
bcd9fd50 396 rinfo = rode->info;
d62a17ae 397 if (rinfo == NULL) {
398 if (isis->debugs & DEBUG_RTE_EVENTS)
399 zlog_debug(
400 "ISIS-Rte: tried to delete non-existant route %s",
401 buff);
402 return;
403 }
404
405 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
406 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
407 if (isis->debugs & DEBUG_RTE_EVENTS)
408 zlog_debug("ISIS-Rte: route delete %s", buff);
321c1bbb 409 isis_zebra_route_update(prefix, src_p, rinfo);
d62a17ae 410 }
411 isis_route_info_delete(rinfo);
412 rode->info = NULL;
bcd9fd50 413 route_unlock_node(rode);
eb5d44eb 414}
415
3dace42d
CF
416static void _isis_route_verify_table(struct isis_area *area,
417 struct route_table *table,
418 struct route_table **tables)
eb5d44eb 419{
d62a17ae 420 struct route_node *rnode, *drnode;
421 struct isis_route_info *rinfo;
321c1bbb 422 char buff[SRCDEST2STR_BUFFER];
d62a17ae 423
321c1bbb
CF
424 for (rnode = route_top(table); rnode;
425 rnode = srcdest_route_next(rnode)) {
d62a17ae 426 if (rnode->info == NULL)
427 continue;
428 rinfo = rnode->info;
429
321c1bbb
CF
430 struct prefix *dst_p;
431 struct prefix_ipv6 *src_p;
432
433 srcdest_rnode_prefixes(rnode,
434 (const struct prefix **)&dst_p,
435 (const struct prefix **)&src_p);
436
d62a17ae 437 if (isis->debugs & DEBUG_RTE_EVENTS) {
321c1bbb 438 srcdest2str(dst_p, src_p, buff, sizeof(buff));
d62a17ae 439 zlog_debug(
440 "ISIS-Rte (%s): route validate: %s %s %s %s",
441 area->area_tag,
442 (CHECK_FLAG(rinfo->flag,
443 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
444 ? "synced"
445 : "not-synced"),
446 (CHECK_FLAG(rinfo->flag,
447 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
448 ? "resync"
449 : "not-resync"),
450 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
451 ? "active"
452 : "inactive"),
453 buff);
454 }
455
321c1bbb 456 isis_zebra_route_update(dst_p, src_p, rinfo);
bcd9fd50
CF
457
458 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
459 continue;
460
461 /* Area is either L1 or L2 => we use level route tables
462 * directly for
463 * validating => no problems with deleting routes. */
464 if (!tables) {
465 isis_route_delete(rnode, table);
466 continue;
467 }
468
469 /* If area is L1L2, we work with merge table and
470 * therefore must
471 * delete node from level tables as well before deleting
472 * route info. */
473 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
474 drnode = srcdest_rnode_lookup(tables[level - 1],
475 dst_p, src_p);
476 if (!drnode)
d62a17ae 477 continue;
3dace42d 478
bcd9fd50 479 route_unlock_node(drnode);
d62a17ae 480
bcd9fd50
CF
481 if (drnode->info != rnode->info)
482 continue;
483
484 drnode->info = NULL;
485 route_unlock_node(drnode);
d62a17ae 486 }
bcd9fd50
CF
487
488 isis_route_delete(rnode, table);
f390d2c7 489 }
fac1f7cc 490}
491
3dace42d
CF
492void isis_route_verify_table(struct isis_area *area, struct route_table *table)
493{
d90b788e 494 _isis_route_verify_table(area, table, NULL);
3dace42d
CF
495}
496
fac1f7cc 497/* Function to validate route tables for L1L2 areas. In this case we can't use
498 * level route tables directly, we have to merge them at first. L1 routes are
499 * preferred over the L2 ones.
500 *
501 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
502 * merge table at first, then L2 paths are added if L1 path for same prefix
503 * doesn't already exists there.
504 *
505 * FIXME: Is it right place to do it at all? Maybe we should push both levels
506 * to the RIB with different zebra route types and let RIB handle this? */
3dace42d
CF
507void isis_route_verify_merge(struct isis_area *area,
508 struct route_table *level1_table,
509 struct route_table *level2_table)
fac1f7cc 510{
3dace42d 511 struct route_table *tables[] = { level1_table, level2_table };
d62a17ae 512 struct route_table *merge;
513 struct route_node *rnode, *mrnode;
514
321c1bbb 515 merge = srcdest_table_init();
d62a17ae 516
3dace42d
CF
517 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
518 for (rnode = route_top(tables[level - 1]); rnode;
321c1bbb 519 rnode = srcdest_route_next(rnode)) {
26b0598f
CF
520 struct isis_route_info *rinfo = rnode->info;
521 if (!rinfo)
3dace42d 522 continue;
26b0598f 523
321c1bbb
CF
524 struct prefix *prefix;
525 struct prefix_ipv6 *src_p;
526
527 srcdest_rnode_prefixes(rnode,
528 (const struct prefix **)&prefix,
529 (const struct prefix **)&src_p);
530 mrnode = srcdest_rnode_get(merge, prefix, src_p);
26b0598f
CF
531 struct isis_route_info *mrinfo = mrnode->info;
532 if (mrinfo) {
3dace42d 533 route_unlock_node(mrnode);
26b0598f
CF
534 if (CHECK_FLAG(mrinfo->flag,
535 ISIS_ROUTE_FLAG_ACTIVE)) {
536 /* Clear the ZEBRA_SYNCED flag on the
537 * L2 route when L1 wins, otherwise L2
538 * won't get reinstalled when L1
539 * disappears.
540 */
541 UNSET_FLAG(
542 rinfo->flag,
543 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
544 );
545 continue;
e02e0871
EDP
546 } else if (CHECK_FLAG(rinfo->flag,
547 ISIS_ROUTE_FLAG_ACTIVE)) {
26b0598f
CF
548 /* Clear the ZEBRA_SYNCED flag on the L1
549 * route when L2 wins, otherwise L1
550 * won't get reinstalled when it
551 * reappears.
552 */
553 UNSET_FLAG(
554 mrinfo->flag,
555 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
556 );
e02e0871
EDP
557 } else if (
558 CHECK_FLAG(
559 mrinfo->flag,
560 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
561 continue;
26b0598f 562 }
3dace42d
CF
563 }
564 mrnode->info = rnode->info;
565 }
d62a17ae 566 }
567
3dace42d 568 _isis_route_verify_table(area, merge, tables);
d62a17ae 569 route_table_finish(merge);
fac1f7cc 570}
571
d62a17ae 572void isis_route_invalidate_table(struct isis_area *area,
573 struct route_table *table)
3f045a08 574{
d62a17ae 575 struct route_node *rode;
576 struct isis_route_info *rinfo;
321c1bbb 577 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
d62a17ae 578 if (rode->info == NULL)
579 continue;
580 rinfo = rode->info;
581
582 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
583 }
3f045a08 584}