2 * IS-IS Rout(e)ing protocol - isis_route.c
3 * Copyright (C) 2001,2002 Sampo Saaristo
4 * Tampere University of Technology
5 * Institute of Communications Engineering
7 * based on ../ospf6d/ospf6_route.[ch]
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)
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
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
31 #include "lib_errors.h"
37 #include "srcdest_table.h"
39 #include "isis_constants.h"
40 #include "isis_common.h"
41 #include "isis_flags.h"
43 #include "isis_misc.h"
44 #include "isis_adjacency.h"
45 #include "isis_circuit.h"
49 #include "isis_spf_private.h"
50 #include "isis_route.h"
51 #include "isis_zebra.h"
53 DEFINE_MTYPE_STATIC(ISISD
, ISIS_NEXTHOP
, "ISIS nexthop");
54 DEFINE_MTYPE_STATIC(ISISD
, ISIS_ROUTE_INFO
, "ISIS route info");
56 DEFINE_HOOK(isis_route_update_hook
,
57 (struct isis_area
* area
, struct prefix
*prefix
,
58 struct isis_route_info
*route_info
),
59 (area
, prefix
, route_info
));
61 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
62 union g_addr
*ip
, ifindex_t ifindex
);
63 static void isis_route_update(struct isis_area
*area
, struct prefix
*prefix
,
64 struct prefix_ipv6
*src_p
,
65 struct isis_route_info
*route_info
);
67 static struct isis_nexthop
*isis_nexthop_create(int family
, union g_addr
*ip
,
70 struct isis_nexthop
*nexthop
;
72 nexthop
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
74 nexthop
->family
= family
;
75 nexthop
->ifindex
= ifindex
;
81 void isis_nexthop_delete(struct isis_nexthop
*nexthop
)
83 XFREE(MTYPE_ISIS_NEXTHOP_LABELS
, nexthop
->label_stack
);
84 XFREE(MTYPE_ISIS_NEXTHOP
, nexthop
);
87 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
88 union g_addr
*ip
, ifindex_t ifindex
)
90 struct listnode
*node
;
91 struct isis_nexthop
*nh
;
93 for (ALL_LIST_ELEMENTS_RO(nexthops
, node
, nh
)) {
94 if (nh
->ifindex
!= ifindex
)
97 /* if the IP is unspecified, return the first nexthop found on
103 if (nh
->family
!= family
)
108 if (IPV4_ADDR_CMP(&nh
->ip
.ipv4
, &ip
->ipv4
))
112 if (IPV6_ADDR_CMP(&nh
->ip
.ipv6
, &ip
->ipv6
))
116 flog_err(EC_LIB_DEVELOPMENT
,
117 "%s: unknown address family [%d]", __func__
,
128 void adjinfo2nexthop(int family
, struct list
*nexthops
,
129 struct isis_adjacency
*adj
, struct isis_sr_psid_info
*sr
,
130 struct mpls_label_stack
*label_stack
)
132 struct isis_nexthop
*nh
;
133 union g_addr ip
= {};
137 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
; i
++) {
138 ip
.ipv4
= adj
->ipv4_addresses
[i
];
140 if (!nexthoplookup(nexthops
, AF_INET
, &ip
,
141 adj
->circuit
->interface
->ifindex
)) {
142 nh
= isis_nexthop_create(
144 adj
->circuit
->interface
->ifindex
);
145 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
148 nh
->label_stack
= label_stack
;
149 listnode_add(nexthops
, nh
);
155 for (unsigned int i
= 0; i
< adj
->ll_ipv6_count
; i
++) {
156 ip
.ipv6
= adj
->ll_ipv6_addrs
[i
];
158 if (!nexthoplookup(nexthops
, AF_INET6
, &ip
,
159 adj
->circuit
->interface
->ifindex
)) {
160 nh
= isis_nexthop_create(
162 adj
->circuit
->interface
->ifindex
);
163 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
166 nh
->label_stack
= label_stack
;
167 listnode_add(nexthops
, nh
);
173 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown address family [%d]",
179 static void isis_route_add_dummy_nexthops(struct isis_route_info
*rinfo
,
180 const uint8_t *sysid
,
181 struct isis_sr_psid_info
*sr
,
182 struct mpls_label_stack
*label_stack
)
184 struct isis_nexthop
*nh
;
186 nh
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
187 memcpy(nh
->sysid
, sysid
, sizeof(nh
->sysid
));
189 nh
->label_stack
= label_stack
;
190 listnode_add(rinfo
->nexthops
, nh
);
193 static struct isis_route_info
*
194 isis_route_info_new(struct prefix
*prefix
, struct prefix_ipv6
*src_p
,
195 uint32_t cost
, uint32_t depth
, struct isis_sr_psid_info
*sr
,
196 struct list
*adjacencies
, bool allow_ecmp
)
198 struct isis_route_info
*rinfo
;
199 struct isis_vertex_adj
*vadj
;
200 struct listnode
*node
;
202 rinfo
= XCALLOC(MTYPE_ISIS_ROUTE_INFO
, sizeof(struct isis_route_info
));
204 rinfo
->nexthops
= list_new();
205 for (ALL_LIST_ELEMENTS_RO(adjacencies
, node
, vadj
)) {
206 struct isis_spf_adj
*sadj
= vadj
->sadj
;
207 struct isis_adjacency
*adj
= sadj
->adj
;
208 struct isis_sr_psid_info
*sr
= &vadj
->sr
;
209 struct mpls_label_stack
*label_stack
= vadj
->label_stack
;
212 * Create dummy nexthops when running SPF on a testing
215 if (CHECK_FLAG(im
->options
, F_ISIS_UNIT_TEST
)) {
216 isis_route_add_dummy_nexthops(rinfo
, sadj
->id
, sr
,
223 /* check for force resync this route */
224 if (CHECK_FLAG(adj
->circuit
->flags
,
225 ISIS_CIRCUIT_FLAPPED_AFTER_SPF
))
226 SET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
228 /* update neighbor router address */
229 switch (prefix
->family
) {
231 if (depth
== 2 && prefix
->prefixlen
== IPV4_MAX_BITLEN
)
232 adj
->router_address
= prefix
->u
.prefix4
;
235 if (depth
== 2 && prefix
->prefixlen
== IPV6_MAX_BITLEN
236 && (!src_p
|| !src_p
->prefixlen
)) {
237 adj
->router_address6
= prefix
->u
.prefix6
;
241 flog_err(EC_LIB_DEVELOPMENT
,
242 "%s: unknown address family [%d]", __func__
,
246 adjinfo2nexthop(prefix
->family
, rinfo
->nexthops
, adj
, sr
,
253 rinfo
->depth
= depth
;
259 static void isis_route_info_delete(struct isis_route_info
*route_info
)
261 if (route_info
->nexthops
) {
262 route_info
->nexthops
->del
=
263 (void (*)(void *))isis_nexthop_delete
;
264 list_delete(&route_info
->nexthops
);
267 XFREE(MTYPE_ISIS_ROUTE_INFO
, route_info
);
270 void isis_route_node_cleanup(struct route_table
*table
, struct route_node
*node
)
273 isis_route_info_delete(node
->info
);
276 static bool isis_sr_psid_info_same(struct isis_sr_psid_info
*new,
277 struct isis_sr_psid_info
*old
)
279 if (new->present
!= old
->present
)
282 if (new->label
!= old
->label
)
285 if (new->sid
.flags
!= old
->sid
.flags
286 || new->sid
.value
!= old
->sid
.value
)
292 static bool isis_label_stack_same(struct mpls_label_stack
*new,
293 struct mpls_label_stack
*old
)
299 if (new->num_labels
!= old
->num_labels
)
301 if (memcmp(&new->label
, &old
->label
,
302 sizeof(mpls_label_t
) * new->num_labels
))
308 static int isis_route_info_same(struct isis_route_info
*new,
309 struct isis_route_info
*old
, char *buf
,
312 struct listnode
*node
;
313 struct isis_nexthop
*new_nh
, *old_nh
;
315 if (new->cost
!= old
->cost
) {
317 snprintf(buf
, buf_size
, "cost (old: %u, new: %u)",
318 old
->cost
, new->cost
);
322 if (new->depth
!= old
->depth
) {
324 snprintf(buf
, buf_size
, "depth (old: %u, new: %u)",
325 old
->depth
, new->depth
);
329 if (!isis_sr_psid_info_same(&new->sr
, &old
->sr
)) {
331 snprintf(buf
, buf_size
, "SR input label");
335 if (new->nexthops
->count
!= old
->nexthops
->count
) {
337 snprintf(buf
, buf_size
, "nhops num (old: %u, new: %u)",
338 old
->nexthops
->count
, new->nexthops
->count
);
342 for (ALL_LIST_ELEMENTS_RO(new->nexthops
, node
, new_nh
)) {
343 old_nh
= nexthoplookup(old
->nexthops
, new_nh
->family
,
344 &new_nh
->ip
, new_nh
->ifindex
);
347 snprintf(buf
, buf_size
,
348 "new nhop"); /* TODO: print nhop */
351 if (!isis_sr_psid_info_same(&new_nh
->sr
, &old_nh
->sr
)) {
353 snprintf(buf
, buf_size
, "nhop SR label");
356 if (!isis_label_stack_same(new_nh
->label_stack
,
357 old_nh
->label_stack
)) {
359 snprintf(buf
, buf_size
, "nhop label stack");
364 /* only the resync flag needs to be checked */
365 if (CHECK_FLAG(new->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
366 != CHECK_FLAG(old
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)) {
368 snprintf(buf
, buf_size
, "resync flag");
375 struct isis_route_info
*
376 isis_route_create(struct prefix
*prefix
, struct prefix_ipv6
*src_p
,
377 uint32_t cost
, uint32_t depth
, struct isis_sr_psid_info
*sr
,
378 struct list
*adjacencies
, bool allow_ecmp
,
379 struct isis_area
*area
, struct route_table
*table
)
381 struct route_node
*route_node
;
382 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
388 rinfo_new
= isis_route_info_new(prefix
, src_p
, cost
, depth
, sr
,
389 adjacencies
, allow_ecmp
);
390 route_node
= srcdest_rnode_get(table
, prefix
, src_p
);
392 rinfo_old
= route_node
->info
;
394 if (IS_DEBUG_RTE_EVENTS
)
395 zlog_debug("ISIS-Rte (%s) route created: %pFX",
396 area
->area_tag
, prefix
);
397 route_info
= rinfo_new
;
398 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
400 route_unlock_node(route_node
);
402 if (IS_DEBUG_RTE_EVENTS
)
403 zlog_debug("ISIS-Rte (%s) route already exists: %pFX",
404 area
->area_tag
, prefix
);
405 #endif /* EXTREME_DEBUG */
406 if (isis_route_info_same(rinfo_new
, rinfo_old
, change_buf
,
407 sizeof(change_buf
))) {
409 if (IS_DEBUG_RTE_EVENTS
)
411 "ISIS-Rte (%s) route unchanged: %pFX",
412 area
->area_tag
, prefix
);
413 #endif /* EXTREME_DEBUG */
414 isis_route_info_delete(rinfo_new
);
415 route_info
= rinfo_old
;
417 if (IS_DEBUG_RTE_EVENTS
)
419 "ISIS-Rte (%s): route changed: %pFX, change: %s",
420 area
->area_tag
, prefix
, change_buf
);
421 rinfo_new
->sr_previous
= rinfo_old
->sr
;
422 isis_route_info_delete(rinfo_old
);
423 route_info
= rinfo_new
;
424 UNSET_FLAG(route_info
->flag
,
425 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
429 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
430 route_node
->info
= route_info
;
435 void isis_route_delete(struct isis_area
*area
, struct route_node
*rode
,
436 struct route_table
*table
)
438 struct isis_route_info
*rinfo
;
439 char buff
[SRCDEST2STR_BUFFER
];
440 struct prefix
*prefix
;
441 struct prefix_ipv6
*src_p
;
444 srcdest_rnode2str(rode
, buff
, sizeof(buff
));
446 srcdest_rnode_prefixes(rode
, (const struct prefix
**)&prefix
,
447 (const struct prefix
**)&src_p
);
451 if (IS_DEBUG_RTE_EVENTS
)
453 "ISIS-Rte: tried to delete non-existent route %s",
458 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
459 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
460 if (IS_DEBUG_RTE_EVENTS
)
461 zlog_debug("ISIS-Rte: route delete %s", buff
);
462 isis_route_update(area
, prefix
, src_p
, rinfo
);
464 isis_route_info_delete(rinfo
);
466 route_unlock_node(rode
);
469 static void isis_route_remove_previous_sid(struct isis_area
*area
,
470 struct prefix
*prefix
,
471 struct isis_route_info
*route_info
)
474 * Explicitly uninstall previous Prefix-SID label if it has
475 * changed or was removed.
477 if (route_info
->sr_previous
.present
&&
478 (!route_info
->sr
.present
||
479 route_info
->sr_previous
.label
!= route_info
->sr
.label
))
480 isis_zebra_prefix_sid_uninstall(area
, prefix
, route_info
,
481 &route_info
->sr_previous
);
484 static void isis_route_update(struct isis_area
*area
, struct prefix
*prefix
,
485 struct prefix_ipv6
*src_p
,
486 struct isis_route_info
*route_info
)
491 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)) {
492 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
495 isis_route_remove_previous_sid(area
, prefix
, route_info
);
498 isis_zebra_route_add_route(area
->isis
, prefix
, src_p
,
500 /* Install/reinstall Prefix-SID label. */
501 if (route_info
->sr
.present
)
502 isis_zebra_prefix_sid_install(area
, prefix
, route_info
,
504 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
506 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
507 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
509 /* Uninstall Prefix-SID label. */
510 if (route_info
->sr
.present
)
511 isis_zebra_prefix_sid_uninstall(
512 area
, prefix
, route_info
, &route_info
->sr
);
513 /* Uninstall route. */
514 isis_zebra_route_del_route(area
->isis
, prefix
, src_p
,
516 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
518 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
522 static void _isis_route_verify_table(struct isis_area
*area
,
523 struct route_table
*table
,
524 struct route_table
*table_backup
,
525 struct route_table
**tables
)
527 struct route_node
*rnode
, *drnode
;
528 struct isis_route_info
*rinfo
;
530 char buff
[SRCDEST2STR_BUFFER
];
531 #endif /* EXTREME_DEBUG */
533 for (rnode
= route_top(table
); rnode
;
534 rnode
= srcdest_route_next(rnode
)) {
535 if (rnode
->info
== NULL
)
539 struct prefix
*dst_p
;
540 struct prefix_ipv6
*src_p
;
542 srcdest_rnode_prefixes(rnode
,
543 (const struct prefix
**)&dst_p
,
544 (const struct prefix
**)&src_p
);
546 /* Link primary route to backup route. */
548 struct route_node
*rnode_bck
;
550 rnode_bck
= srcdest_rnode_lookup(table_backup
, dst_p
,
553 rinfo
->backup
= rnode_bck
->info
;
554 UNSET_FLAG(rinfo
->flag
,
555 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
556 } else if (rinfo
->backup
) {
557 rinfo
->backup
= NULL
;
558 UNSET_FLAG(rinfo
->flag
,
559 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
564 if (IS_DEBUG_RTE_EVENTS
) {
565 srcdest2str(dst_p
, src_p
, buff
, sizeof(buff
));
567 "ISIS-Rte (%s): route validate: %s %s %s %s",
569 (CHECK_FLAG(rinfo
->flag
,
570 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)
573 (CHECK_FLAG(rinfo
->flag
,
574 ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
577 (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)
582 #endif /* EXTREME_DEBUG */
584 isis_route_update(area
, dst_p
, src_p
, rinfo
);
586 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
589 /* Area is either L1 or L2 => we use level route tables
591 * validating => no problems with deleting routes. */
593 isis_route_delete(area
, rnode
, table
);
597 /* If area is L1L2, we work with merge table and
599 * delete node from level tables as well before deleting
601 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
602 drnode
= srcdest_rnode_lookup(tables
[level
- 1],
607 route_unlock_node(drnode
);
609 if (drnode
->info
!= rnode
->info
)
613 route_unlock_node(drnode
);
616 isis_route_delete(area
, rnode
, table
);
620 void isis_route_verify_table(struct isis_area
*area
, struct route_table
*table
,
621 struct route_table
*table_backup
)
623 _isis_route_verify_table(area
, table
, table_backup
, NULL
);
626 /* Function to validate route tables for L1L2 areas. In this case we can't use
627 * level route tables directly, we have to merge them at first. L1 routes are
628 * preferred over the L2 ones.
630 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
631 * merge table at first, then L2 paths are added if L1 path for same prefix
632 * doesn't already exists there.
634 * FIXME: Is it right place to do it at all? Maybe we should push both levels
635 * to the RIB with different zebra route types and let RIB handle this? */
636 void isis_route_verify_merge(struct isis_area
*area
,
637 struct route_table
*level1_table
,
638 struct route_table
*level1_table_backup
,
639 struct route_table
*level2_table
,
640 struct route_table
*level2_table_backup
)
642 struct route_table
*tables
[] = {level1_table
, level2_table
};
643 struct route_table
*tables_backup
[] = {level1_table_backup
,
644 level2_table_backup
};
645 struct route_table
*merge
;
646 struct route_node
*rnode
, *mrnode
;
648 merge
= srcdest_table_init();
650 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
651 for (rnode
= route_top(tables
[level
- 1]); rnode
;
652 rnode
= srcdest_route_next(rnode
)) {
653 struct isis_route_info
*rinfo
= rnode
->info
;
654 struct route_node
*rnode_bck
;
659 struct prefix
*prefix
;
660 struct prefix_ipv6
*src_p
;
662 srcdest_rnode_prefixes(rnode
,
663 (const struct prefix
**)&prefix
,
664 (const struct prefix
**)&src_p
);
666 /* Link primary route to backup route. */
667 rnode_bck
= srcdest_rnode_lookup(
668 tables_backup
[level
- 1], prefix
, src_p
);
670 rinfo
->backup
= rnode_bck
->info
;
671 UNSET_FLAG(rinfo
->flag
,
672 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
673 } else if (rinfo
->backup
) {
674 rinfo
->backup
= NULL
;
675 UNSET_FLAG(rinfo
->flag
,
676 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
679 mrnode
= srcdest_rnode_get(merge
, prefix
, src_p
);
680 struct isis_route_info
*mrinfo
= mrnode
->info
;
682 route_unlock_node(mrnode
);
683 if (CHECK_FLAG(mrinfo
->flag
,
684 ISIS_ROUTE_FLAG_ACTIVE
)) {
685 /* Clear the ZEBRA_SYNCED flag on the
686 * L2 route when L1 wins, otherwise L2
687 * won't get reinstalled when L1
692 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
695 } else if (CHECK_FLAG(rinfo
->flag
,
696 ISIS_ROUTE_FLAG_ACTIVE
)) {
697 /* Clear the ZEBRA_SYNCED flag on the L1
698 * route when L2 wins, otherwise L1
699 * won't get reinstalled when it
704 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
709 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
713 mrnode
->info
= rnode
->info
;
717 _isis_route_verify_table(area
, merge
, NULL
, tables
);
718 route_table_finish(merge
);
721 void isis_route_invalidate_table(struct isis_area
*area
,
722 struct route_table
*table
)
724 struct route_node
*rode
;
725 struct isis_route_info
*rinfo
;
726 for (rode
= route_top(table
); rode
; rode
= srcdest_route_next(rode
)) {
727 if (rode
->info
== NULL
)
732 rinfo
->backup
= NULL
;
734 * For now, always force routes that have backup
735 * nexthops to be reinstalled.
737 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
739 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
743 void isis_route_switchover_nexthop(struct isis_area
*area
,
744 struct route_table
*table
, int family
,
745 union g_addr
*nexthop_addr
,
748 const char *ifname
= NULL
, *vrfname
= NULL
;
749 struct isis_route_info
*rinfo
;
750 struct prefix_ipv6
*src_p
;
751 struct route_node
*rnode
;
753 struct prefix
*prefix
;
755 if (IS_DEBUG_EVENTS
) {
756 if (area
&& area
->isis
) {
757 vrf_id
= area
->isis
->vrf_id
;
758 vrfname
= vrf_id_to_name(vrf_id
);
759 ifname
= ifindex2ifname(ifindex
, vrf_id
);
761 zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
762 __func__
, family2str(family
), vrfname
? vrfname
: "",
763 ifname
? ifname
: "");
766 for (rnode
= route_top(table
); rnode
;
767 rnode
= srcdest_route_next(rnode
)) {
775 if (!nexthoplookup(rinfo
->nexthops
, family
, nexthop_addr
,
779 srcdest_rnode_prefixes(rnode
, (const struct prefix
**)&prefix
,
780 (const struct prefix
**)&src_p
);
782 /* Switchover route. */
783 isis_route_remove_previous_sid(area
, prefix
, rinfo
);
784 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
785 isis_route_update(area
, prefix
, src_p
, rinfo
->backup
);
787 isis_route_info_delete(rinfo
);
790 route_unlock_node(rnode
);