]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_route.c
Merge pull request #13366 from zmw12306/rte_tag
[mirror_frr.git] / isisd / isis_route.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
eb5d44eb 2/*
3 * IS-IS Rout(e)ing protocol - isis_route.c
4 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 5 * Tampere University of Technology
eb5d44eb 6 * Institute of Communications Engineering
7 *
8 * based on ../ospf6d/ospf6_route.[ch]
9 * by Yasuhiro Ohara
eb5d44eb 10 */
11
eb5d44eb 12#include <zebra.h>
eb5d44eb 13
24a58196 14#include "frrevent.h"
eb5d44eb 15#include "linklist.h"
16#include "vty.h"
17#include "log.h"
363be4dd 18#include "lib_errors.h"
eb5d44eb 19#include "memory.h"
20#include "prefix.h"
21#include "hash.h"
22#include "if.h"
23#include "table.h"
321c1bbb 24#include "srcdest_table.h"
eb5d44eb 25
26#include "isis_constants.h"
27#include "isis_common.h"
3f045a08 28#include "isis_flags.h"
eb5d44eb 29#include "isisd.h"
30#include "isis_misc.h"
31#include "isis_adjacency.h"
32#include "isis_circuit.h"
eb5d44eb 33#include "isis_pdu.h"
34#include "isis_lsp.h"
35#include "isis_spf.h"
7b36d36e 36#include "isis_spf_private.h"
eb5d44eb 37#include "isis_route.h"
38#include "isis_zebra.h"
80ef2e89 39#include "isis_flex_algo.h"
eb5d44eb 40
66b9a381
DL
41DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
42DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
7153c3ca
HS
43DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_TABLE_INFO, "ISIS route table info");
44
66b9a381 45
6cf38339
RW
46DEFINE_HOOK(isis_route_update_hook,
47 (struct isis_area * area, struct prefix *prefix,
48 struct isis_route_info *route_info),
8451921b 49 (area, prefix, route_info));
6cf38339 50
363be4dd
RW
51static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
52 union g_addr *ip, ifindex_t ifindex);
6cf38339
RW
53static void isis_route_update(struct isis_area *area, struct prefix *prefix,
54 struct prefix_ipv6 *src_p,
0a5f3f4f 55 struct isis_route_info *route_info);
9e1194c2 56
7153c3ca
HS
57static struct mpls_label_stack *
58label_stack_dup(const struct mpls_label_stack *const orig)
59{
60 struct mpls_label_stack *copy;
61 int array_size;
62
63 if (orig == NULL)
64 return NULL;
65
66 array_size = orig->num_labels * sizeof(mpls_label_t);
67 copy = XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
68 sizeof(struct mpls_label_stack) + array_size);
69 copy->num_labels = orig->num_labels;
70 memcpy(copy->label, orig->label, array_size);
71 return copy;
72}
73
74static struct isis_nexthop *
75isis_nexthop_create(int family, const union g_addr *const ip, ifindex_t ifindex)
eb5d44eb 76{
d62a17ae 77 struct isis_nexthop *nexthop;
f390d2c7 78
d62a17ae 79 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
f390d2c7 80
363be4dd 81 nexthop->family = family;
d62a17ae 82 nexthop->ifindex = ifindex;
363be4dd 83 nexthop->ip = *ip;
eb5d44eb 84
d62a17ae 85 return nexthop;
eb5d44eb 86}
87
7153c3ca
HS
88static struct isis_nexthop *
89isis_nexthop_dup(const struct isis_nexthop *const orig)
90{
91 struct isis_nexthop *nexthop;
92
93 nexthop = isis_nexthop_create(orig->family, &orig->ip, orig->ifindex);
94 memcpy(nexthop->sysid, orig->sysid, ISIS_SYS_ID_LEN);
95 nexthop->sr = orig->sr;
96 nexthop->label_stack = label_stack_dup(orig->label_stack);
97
98 return nexthop;
99}
100
c951ee6e 101void isis_nexthop_delete(struct isis_nexthop *nexthop)
eb5d44eb 102{
c951ee6e 103 XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
885e2413 104 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
eb5d44eb 105}
106
7153c3ca
HS
107static struct list *isis_nexthop_list_dup(const struct list *orig)
108{
109 struct list *copy;
110 struct listnode *node;
111 struct isis_nexthop *nh;
112 struct isis_nexthop *nhcopy;
113
114 copy = list_new();
115 for (ALL_LIST_ELEMENTS_RO(orig, node, nh)) {
116 nhcopy = isis_nexthop_dup(nh);
117 listnode_add(copy, nhcopy);
118 }
119 return copy;
120}
121
363be4dd
RW
122static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
123 union g_addr *ip, ifindex_t ifindex)
eb5d44eb 124{
d62a17ae 125 struct listnode *node;
126 struct isis_nexthop *nh;
eb5d44eb 127
d62a17ae 128 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
74b95643
DA
129 if (nh->ifindex != ifindex)
130 continue;
a11742dc 131
5389c4f7
LS
132 /* if the IP is unspecified, return the first nexthop found on
133 * the interface
134 */
135 if (!ip)
136 return nh;
137
138 if (nh->family != family)
139 continue;
140
363be4dd
RW
141 switch (family) {
142 case AF_INET:
143 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
144 continue;
145 break;
146 case AF_INET6:
147 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
148 continue;
149 break;
150 default:
151 flog_err(EC_LIB_DEVELOPMENT,
152 "%s: unknown address family [%d]", __func__,
153 family);
154 exit(1);
155 }
eb5d44eb 156
363be4dd 157 return nh;
d62a17ae 158 }
eb5d44eb 159
9e1194c2 160 return NULL;
eb5d44eb 161}
162
c951ee6e 163void adjinfo2nexthop(int family, struct list *nexthops,
d47d6089 164 struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
c951ee6e 165 struct mpls_label_stack *label_stack)
eb5d44eb 166{
d62a17ae 167 struct isis_nexthop *nh;
363be4dd
RW
168 union g_addr ip = {};
169
170 switch (family) {
171 case AF_INET:
172 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
173 ip.ipv4 = adj->ipv4_addresses[i];
174
175 if (!nexthoplookup(nexthops, AF_INET, &ip,
176 adj->circuit->interface->ifindex)) {
177 nh = isis_nexthop_create(
178 AF_INET, &ip,
179 adj->circuit->interface->ifindex);
26f6acaf 180 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
d47d6089
RW
181 if (sr)
182 nh->sr = *sr;
c951ee6e 183 nh->label_stack = label_stack;
363be4dd
RW
184 listnode_add(nexthops, nh);
185 break;
186 }
d62a17ae 187 }
363be4dd
RW
188 break;
189 case AF_INET6:
173f8887
OD
190 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
191 ip.ipv6 = adj->ll_ipv6_addrs[i];
363be4dd
RW
192
193 if (!nexthoplookup(nexthops, AF_INET6, &ip,
194 adj->circuit->interface->ifindex)) {
195 nh = isis_nexthop_create(
196 AF_INET6, &ip,
197 adj->circuit->interface->ifindex);
26f6acaf 198 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
d47d6089
RW
199 if (sr)
200 nh->sr = *sr;
c951ee6e 201 nh->label_stack = label_stack;
363be4dd
RW
202 listnode_add(nexthops, nh);
203 break;
204 }
d62a17ae 205 }
363be4dd
RW
206 break;
207 default:
208 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
209 __func__, family);
210 exit(1);
f390d2c7 211 }
eb5d44eb 212}
eb5d44eb 213
52a7c25e 214static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
c951ee6e 215 const uint8_t *sysid,
d47d6089 216 struct isis_sr_psid_info *sr,
c951ee6e 217 struct mpls_label_stack *label_stack)
52a7c25e
RW
218{
219 struct isis_nexthop *nh;
220
221 nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
222 memcpy(nh->sysid, sysid, sizeof(nh->sysid));
d47d6089 223 nh->sr = *sr;
c951ee6e 224 nh->label_stack = label_stack;
52a7c25e
RW
225 listnode_add(rinfo->nexthops, nh);
226}
227
d47d6089
RW
228static struct isis_route_info *
229isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
230 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
e886416f 231 struct list *adjacencies, bool allow_ecmp)
eb5d44eb 232{
d62a17ae 233 struct isis_route_info *rinfo;
7b36d36e 234 struct isis_vertex_adj *vadj;
d62a17ae 235 struct listnode *node;
236
237 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
238
363be4dd 239 rinfo->nexthops = list_new();
7b36d36e
RW
240 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
241 struct isis_spf_adj *sadj = vadj->sadj;
242 struct isis_adjacency *adj = sadj->adj;
d47d6089 243 struct isis_sr_psid_info *sr = &vadj->sr;
c951ee6e 244 struct mpls_label_stack *label_stack = vadj->label_stack;
7b36d36e 245
52a7c25e
RW
246 /*
247 * Create dummy nexthops when running SPF on a testing
248 * environment.
249 */
250 if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
d47d6089 251 isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
c951ee6e 252 label_stack);
e886416f
RW
253 if (!allow_ecmp)
254 break;
52a7c25e
RW
255 continue;
256 }
257
363be4dd
RW
258 /* check for force resync this route */
259 if (CHECK_FLAG(adj->circuit->flags,
260 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
261 SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
262
263 /* update neighbor router address */
264 switch (prefix->family) {
265 case AF_INET:
12256b84 266 if (depth == 2 && prefix->prefixlen == IPV4_MAX_BITLEN)
d62a17ae 267 adj->router_address = prefix->u.prefix4;
363be4dd
RW
268 break;
269 case AF_INET6:
13ccce6e 270 if (depth == 2 && prefix->prefixlen == IPV6_MAX_BITLEN
321c1bbb 271 && (!src_p || !src_p->prefixlen)) {
d62a17ae 272 adj->router_address6 = prefix->u.prefix6;
321c1bbb 273 }
363be4dd
RW
274 break;
275 default:
276 flog_err(EC_LIB_DEVELOPMENT,
277 "%s: unknown address family [%d]", __func__,
278 prefix->family);
279 exit(1);
d62a17ae 280 }
d47d6089 281 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
c951ee6e 282 label_stack);
e886416f
RW
283 if (!allow_ecmp)
284 break;
d62a17ae 285 }
286
287 rinfo->cost = cost;
288 rinfo->depth = depth;
7153c3ca
HS
289 rinfo->sr_algo[sr->algorithm] = *sr;
290 rinfo->sr_algo[sr->algorithm].nexthops = rinfo->nexthops;
291 rinfo->sr_algo[sr->algorithm].nexthops_backup =
bdaafbf8 292 rinfo->backup ? rinfo->backup->nexthops : NULL;
d62a17ae 293
294 return rinfo;
eb5d44eb 295}
296
d62a17ae 297static void isis_route_info_delete(struct isis_route_info *route_info)
eb5d44eb 298{
7153c3ca
HS
299 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
300 if (!route_info->sr_algo[i].present)
301 continue;
302
303 if (route_info->sr_algo[i].nexthops == route_info->nexthops)
304 continue;
305
306 route_info->sr_algo[i].nexthops->del =
307 (void (*)(void *))isis_nexthop_delete;
308 list_delete(&route_info->sr_algo[i].nexthops);
309 }
310
d62a17ae 311 if (route_info->nexthops) {
312 route_info->nexthops->del =
313 (void (*)(void *))isis_nexthop_delete;
6a154c88 314 list_delete(&route_info->nexthops);
d62a17ae 315 }
316
d62a17ae 317 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
eb5d44eb 318}
319
c951ee6e
RW
320void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
321{
322 if (node->info)
323 isis_route_info_delete(node->info);
324}
325
7153c3ca
HS
326struct isis_route_table_info *isis_route_table_info_alloc(uint8_t algorithm)
327{
328 struct isis_route_table_info *info;
329
330 info = XCALLOC(MTYPE_ISIS_ROUTE_TABLE_INFO, sizeof(*info));
331 info->algorithm = algorithm;
332 return info;
333}
334
335void isis_route_table_info_free(void *info)
336{
337 XFREE(MTYPE_ISIS_ROUTE_TABLE_INFO, info);
338}
339
340uint8_t isis_route_table_algorithm(const struct route_table *table)
341{
342 const struct isis_route_table_info *info = table->info;
343
344 return info ? info->algorithm : 0;
345}
346
d47d6089
RW
347static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
348 struct isis_sr_psid_info *old)
349{
350 if (new->present != old->present)
351 return false;
352
353 if (new->label != old->label)
354 return false;
355
356 if (new->sid.flags != old->sid.flags
357 || new->sid.value != old->sid.value)
358 return false;
359
7f8dddf4
HS
360 if (new->sid.algorithm != old->sid.algorithm)
361 return false;
362
d47d6089
RW
363 return true;
364}
365
16fe8cff
RW
366static bool isis_label_stack_same(struct mpls_label_stack *new,
367 struct mpls_label_stack *old)
368{
369 if (!new && !old)
370 return true;
371 if (!new || !old)
372 return false;
373 if (new->num_labels != old->num_labels)
374 return false;
375 if (memcmp(&new->label, &old->label,
376 sizeof(mpls_label_t) * new->num_labels))
377 return false;
378
379 return true;
380}
381
d62a17ae 382static int isis_route_info_same(struct isis_route_info *new,
1b2b2677
EDP
383 struct isis_route_info *old, char *buf,
384 size_t buf_size)
eb5d44eb 385{
d62a17ae 386 struct listnode *node;
d47d6089 387 struct isis_nexthop *new_nh, *old_nh;
d62a17ae 388
1b2b2677
EDP
389 if (new->cost != old->cost) {
390 if (buf)
391 snprintf(buf, buf_size, "cost (old: %u, new: %u)",
392 old->cost, new->cost);
d62a17ae 393 return 0;
1b2b2677 394 }
d62a17ae 395
1b2b2677
EDP
396 if (new->depth != old->depth) {
397 if (buf)
398 snprintf(buf, buf_size, "depth (old: %u, new: %u)",
399 old->depth, new->depth);
d62a17ae 400 return 0;
1b2b2677 401 }
d62a17ae 402
7153c3ca
HS
403 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
404 struct isis_sr_psid_info new_sr_algo;
405 struct isis_sr_psid_info old_sr_algo;
406
407 new_sr_algo = new->sr_algo[i];
408 old_sr_algo = old->sr_algo[i];
409
410 if (!isis_sr_psid_info_same(&new_sr_algo, &old_sr_algo)) {
411 if (buf)
412 snprintf(
413 buf, buf_size,
414 "SR input label algo-%u (old: %s, new: %s)",
415 i, old_sr_algo.present ? "yes" : "no",
416 new_sr_algo.present ? "yes" : "no");
417 return 0;
418 }
d47d6089
RW
419 }
420
1b2b2677
EDP
421 if (new->nexthops->count != old->nexthops->count) {
422 if (buf)
423 snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
424 old->nexthops->count, new->nexthops->count);
d62a17ae 425 return 0;
1b2b2677 426 }
d62a17ae 427
d47d6089
RW
428 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
429 old_nh = nexthoplookup(old->nexthops, new_nh->family,
430 &new_nh->ip, new_nh->ifindex);
431 if (!old_nh) {
1b2b2677
EDP
432 if (buf)
433 snprintf(buf, buf_size,
434 "new nhop"); /* TODO: print nhop */
363be4dd 435 return 0;
1b2b2677 436 }
d47d6089
RW
437 if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
438 if (buf)
439 snprintf(buf, buf_size, "nhop SR label");
440 return 0;
441 }
16fe8cff
RW
442 if (!isis_label_stack_same(new_nh->label_stack,
443 old_nh->label_stack)) {
444 if (buf)
445 snprintf(buf, buf_size, "nhop label stack");
446 return 0;
447 }
1b2b2677 448 }
363be4dd 449
1b2b2677
EDP
450 /* only the resync flag needs to be checked */
451 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
452 != CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) {
453 if (buf)
454 snprintf(buf, buf_size, "resync flag");
455 return 0;
456 }
d62a17ae 457
458 return 1;
eb5d44eb 459}
460
d47d6089
RW
461struct isis_route_info *
462isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
463 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
e886416f
RW
464 struct list *adjacencies, bool allow_ecmp,
465 struct isis_area *area, struct route_table *table)
eb5d44eb 466{
d62a17ae 467 struct route_node *route_node;
468 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
1b2b2677 469 char change_buf[64];
d62a17ae 470
3dace42d 471 if (!table)
d62a17ae 472 return NULL;
3dace42d 473
d47d6089 474 rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
e886416f 475 adjacencies, allow_ecmp);
321c1bbb 476 route_node = srcdest_rnode_get(table, prefix, src_p);
d62a17ae 477
478 rinfo_old = route_node->info;
479 if (!rinfo_old) {
e740f9c1 480 if (IS_DEBUG_RTE_EVENTS)
2dbe669b
DA
481 zlog_debug("ISIS-Rte (%s) route created: %pFX",
482 area->area_tag, prefix);
d62a17ae 483 route_info = rinfo_new;
484 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
485 } else {
bcd9fd50 486 route_unlock_node(route_node);
1b2b2677 487#ifdef EXTREME_DEBUG
e740f9c1 488 if (IS_DEBUG_RTE_EVENTS)
2dbe669b
DA
489 zlog_debug("ISIS-Rte (%s) route already exists: %pFX",
490 area->area_tag, prefix);
1b2b2677
EDP
491#endif /* EXTREME_DEBUG */
492 if (isis_route_info_same(rinfo_new, rinfo_old, change_buf,
493 sizeof(change_buf))) {
494#ifdef EXTREME_DEBUG
e740f9c1 495 if (IS_DEBUG_RTE_EVENTS)
2dbe669b
DA
496 zlog_debug(
497 "ISIS-Rte (%s) route unchanged: %pFX",
498 area->area_tag, prefix);
1b2b2677 499#endif /* EXTREME_DEBUG */
d62a17ae 500 isis_route_info_delete(rinfo_new);
501 route_info = rinfo_old;
502 } else {
e740f9c1 503 if (IS_DEBUG_RTE_EVENTS)
1b2b2677 504 zlog_debug(
2dbe669b
DA
505 "ISIS-Rte (%s): route changed: %pFX, change: %s",
506 area->area_tag, prefix, change_buf);
7153c3ca
HS
507 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
508 rinfo_new->sr_algo_previous[i] =
509 rinfo_old->sr_algo[i];
d62a17ae 510 isis_route_info_delete(rinfo_old);
511 route_info = rinfo_new;
512 UNSET_FLAG(route_info->flag,
513 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
514 }
515 }
516
517 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
518 route_node->info = route_info;
519
520 return route_info;
eb5d44eb 521}
522
16fe8cff
RW
523void isis_route_delete(struct isis_area *area, struct route_node *rode,
524 struct route_table *table)
eb5d44eb 525{
d62a17ae 526 struct isis_route_info *rinfo;
321c1bbb 527 char buff[SRCDEST2STR_BUFFER];
bcd9fd50
CF
528 struct prefix *prefix;
529 struct prefix_ipv6 *src_p;
d62a17ae 530
531 /* for log */
bcd9fd50 532 srcdest_rnode2str(rode, buff, sizeof(buff));
d62a17ae 533
bcd9fd50
CF
534 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
535 (const struct prefix **)&src_p);
d62a17ae 536
bcd9fd50 537 rinfo = rode->info;
d62a17ae 538 if (rinfo == NULL) {
e740f9c1 539 if (IS_DEBUG_RTE_EVENTS)
d62a17ae 540 zlog_debug(
b97047ed 541 "ISIS-Rte: tried to delete non-existent route %s",
d62a17ae 542 buff);
543 return;
544 }
545
546 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
547 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
e740f9c1 548 if (IS_DEBUG_RTE_EVENTS)
d62a17ae 549 zlog_debug("ISIS-Rte: route delete %s", buff);
6cf38339 550 isis_route_update(area, prefix, src_p, rinfo);
d62a17ae 551 }
552 isis_route_info_delete(rinfo);
553 rode->info = NULL;
bcd9fd50 554 route_unlock_node(rode);
eb5d44eb 555}
556
8a65b22d
LS
557static void isis_route_remove_previous_sid(struct isis_area *area,
558 struct prefix *prefix,
559 struct isis_route_info *route_info)
560{
561 /*
562 * Explicitly uninstall previous Prefix-SID label if it has
563 * changed or was removed.
564 */
7153c3ca
HS
565 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
566 if (route_info->sr_algo_previous[i].present &&
567 (!route_info->sr_algo[i].present ||
568 route_info->sr_algo_previous[i].label !=
569 route_info->sr_algo[i].label))
570 isis_zebra_prefix_sid_uninstall(
571 area, prefix, route_info,
572 &route_info->sr_algo_previous[i]);
573 }
574}
575
576static void set_merge_route_info_sr_algo(struct isis_route_info *mrinfo,
577 struct isis_route_info *rinfo)
578{
579 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
580 if (rinfo->sr_algo[i].present) {
581 assert(i == rinfo->sr_algo[i].algorithm);
582 assert(rinfo->nexthops);
583 assert(rinfo->backup ? rinfo->backup->nexthops != NULL
584 : true);
585
586 if (mrinfo->sr_algo[i].nexthops != NULL &&
587 mrinfo->sr_algo[i].nexthops != mrinfo->nexthops) {
588 mrinfo->sr_algo[i].nexthops->del =
589 (void (*)(void *))isis_nexthop_delete;
590 list_delete(&mrinfo->sr_algo[i].nexthops);
591 }
592
593 mrinfo->sr_algo[i] = rinfo->sr_algo[i];
594 mrinfo->sr_algo[i].nexthops = isis_nexthop_list_dup(
595 rinfo->sr_algo[i].nexthops);
596 }
597 }
598
599 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
600 UNSET_FLAG(mrinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
8a65b22d
LS
601}
602
6cf38339
RW
603static void isis_route_update(struct isis_area *area, struct prefix *prefix,
604 struct prefix_ipv6 *src_p,
0a5f3f4f
RW
605 struct isis_route_info *route_info)
606{
41c2bf85
LS
607 if (area == NULL)
608 return;
609
0a5f3f4f
RW
610 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
611 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
612 return;
613
8a65b22d 614 isis_route_remove_previous_sid(area, prefix, route_info);
d47d6089
RW
615
616 /* Install route. */
41c2bf85
LS
617 isis_zebra_route_add_route(area->isis, prefix, src_p,
618 route_info);
7153c3ca
HS
619
620 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
621 struct isis_sr_psid_info sr_algo;
622
623 sr_algo = route_info->sr_algo[i];
624
625 /*
626 * Install/reinstall Prefix-SID label.
627 */
628 if (sr_algo.present)
629 isis_zebra_prefix_sid_install(area, prefix,
630 &sr_algo);
631
632 hook_call(isis_route_update_hook, area, prefix,
633 route_info);
634 }
bdaafbf8 635
6cf38339 636 hook_call(isis_route_update_hook, area, prefix, route_info);
0a5f3f4f
RW
637
638 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
639 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
640 } else {
d47d6089 641 /* Uninstall Prefix-SID label. */
7153c3ca
HS
642 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
643 if (route_info->sr_algo[i].present)
644 isis_zebra_prefix_sid_uninstall(
645 area, prefix, route_info,
646 &route_info->sr_algo[i]);
647
d47d6089 648 /* Uninstall route. */
41c2bf85
LS
649 isis_zebra_route_del_route(area->isis, prefix, src_p,
650 route_info);
6cf38339 651 hook_call(isis_route_update_hook, area, prefix, route_info);
0a5f3f4f
RW
652
653 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
654 }
655}
656
3dace42d
CF
657static void _isis_route_verify_table(struct isis_area *area,
658 struct route_table *table,
c951ee6e 659 struct route_table *table_backup,
3dace42d 660 struct route_table **tables)
eb5d44eb 661{
d62a17ae 662 struct route_node *rnode, *drnode;
663 struct isis_route_info *rinfo;
1b2b2677 664#ifdef EXTREME_DEBUG
321c1bbb 665 char buff[SRCDEST2STR_BUFFER];
1b2b2677 666#endif /* EXTREME_DEBUG */
7153c3ca 667 uint8_t algorithm = isis_route_table_algorithm(table);
d62a17ae 668
321c1bbb
CF
669 for (rnode = route_top(table); rnode;
670 rnode = srcdest_route_next(rnode)) {
d62a17ae 671 if (rnode->info == NULL)
672 continue;
673 rinfo = rnode->info;
674
321c1bbb
CF
675 struct prefix *dst_p;
676 struct prefix_ipv6 *src_p;
677
678 srcdest_rnode_prefixes(rnode,
679 (const struct prefix **)&dst_p,
680 (const struct prefix **)&src_p);
681
c951ee6e
RW
682 /* Link primary route to backup route. */
683 if (table_backup) {
684 struct route_node *rnode_bck;
685
686 rnode_bck = srcdest_rnode_lookup(table_backup, dst_p,
687 src_p);
688 if (rnode_bck) {
689 rinfo->backup = rnode_bck->info;
7153c3ca 690 rinfo->sr_algo[algorithm].nexthops_backup =
bdaafbf8 691 rinfo->backup->nexthops;
c951ee6e
RW
692 UNSET_FLAG(rinfo->flag,
693 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
16fe8cff
RW
694 } else if (rinfo->backup) {
695 rinfo->backup = NULL;
7153c3ca
HS
696 rinfo->sr_algo[algorithm].nexthops_backup =
697 NULL;
16fe8cff
RW
698 UNSET_FLAG(rinfo->flag,
699 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
c951ee6e
RW
700 }
701 }
702
1b2b2677 703#ifdef EXTREME_DEBUG
e740f9c1 704 if (IS_DEBUG_RTE_EVENTS) {
321c1bbb 705 srcdest2str(dst_p, src_p, buff, sizeof(buff));
d62a17ae 706 zlog_debug(
707 "ISIS-Rte (%s): route validate: %s %s %s %s",
708 area->area_tag,
709 (CHECK_FLAG(rinfo->flag,
710 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
711 ? "synced"
712 : "not-synced"),
713 (CHECK_FLAG(rinfo->flag,
714 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
715 ? "resync"
716 : "not-resync"),
717 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
718 ? "active"
719 : "inactive"),
720 buff);
721 }
1b2b2677 722#endif /* EXTREME_DEBUG */
d62a17ae 723
6cf38339 724 isis_route_update(area, dst_p, src_p, rinfo);
bcd9fd50
CF
725
726 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
727 continue;
728
80ef2e89 729 /* In case the verify is not for a merge, we use a single table
bcd9fd50
CF
730 * directly for
731 * validating => no problems with deleting routes. */
732 if (!tables) {
6cf38339 733 isis_route_delete(area, rnode, table);
bcd9fd50
CF
734 continue;
735 }
736
80ef2e89
HS
737 /* If we work on a merged table,
738 * therefore we must
739 * delete node from each table as well before deleting
bcd9fd50 740 * route info. */
80ef2e89
HS
741 for (int i = 0; tables[i]; i++) {
742 drnode = srcdest_rnode_lookup(tables[i], dst_p, src_p);
bcd9fd50 743 if (!drnode)
d62a17ae 744 continue;
3dace42d 745
bcd9fd50 746 route_unlock_node(drnode);
d62a17ae 747
bcd9fd50
CF
748 if (drnode->info != rnode->info)
749 continue;
750
751 drnode->info = NULL;
752 route_unlock_node(drnode);
d62a17ae 753 }
bcd9fd50 754
6cf38339 755 isis_route_delete(area, rnode, table);
f390d2c7 756 }
fac1f7cc 757}
758
80ef2e89
HS
759static void _isis_route_verify_merge(struct isis_area *area,
760 struct route_table **tables,
761 struct route_table **tables_backup,
762 int tree);
763
c951ee6e 764void isis_route_verify_table(struct isis_area *area, struct route_table *table,
80ef2e89 765 struct route_table *table_backup, int tree)
3dace42d 766{
80ef2e89
HS
767 struct route_table *tables[SR_ALGORITHM_COUNT] = {table};
768 struct route_table *tables_backup[SR_ALGORITHM_COUNT] = {table_backup};
769#ifndef FABRICD
770 int tables_next = 1;
771 int level = area->is_type == IS_LEVEL_1 ? ISIS_LEVEL1 : ISIS_LEVEL2;
772 struct listnode *node;
773 struct flex_algo *fa;
774 struct isis_flex_algo_data *data;
775
776 for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node, fa)) {
777 data = fa->data;
778 tables[tables_next] =
779 data->spftree[tree][level - 1]->route_table;
780 tables_backup[tables_next] =
781 data->spftree[tree][level - 1]->route_table_backup;
782 _isis_route_verify_table(area, tables[tables_next],
783 tables_backup[tables_next], NULL);
784 tables_next++;
785 }
786#endif /* ifndef FABRICD */
787
788 _isis_route_verify_merge(area, tables, tables_backup, tree);
3dace42d
CF
789}
790
fac1f7cc 791/* Function to validate route tables for L1L2 areas. In this case we can't use
792 * level route tables directly, we have to merge them at first. L1 routes are
793 * preferred over the L2 ones.
794 *
795 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
796 * merge table at first, then L2 paths are added if L1 path for same prefix
797 * doesn't already exists there.
798 *
799 * FIXME: Is it right place to do it at all? Maybe we should push both levels
800 * to the RIB with different zebra route types and let RIB handle this? */
3dace42d
CF
801void isis_route_verify_merge(struct isis_area *area,
802 struct route_table *level1_table,
c951ee6e
RW
803 struct route_table *level1_table_backup,
804 struct route_table *level2_table,
80ef2e89 805 struct route_table *level2_table_backup, int tree)
fac1f7cc 806{
80ef2e89 807 struct route_table *tables[] = {level1_table, level2_table, NULL};
c951ee6e 808 struct route_table *tables_backup[] = {level1_table_backup,
80ef2e89
HS
809 level2_table_backup, NULL};
810 _isis_route_verify_merge(area, tables, tables_backup, tree);
811}
812
813static void _isis_route_verify_merge(struct isis_area *area,
814 struct route_table **tables,
815 struct route_table **tables_backup,
816 int tree)
817{
d62a17ae 818 struct route_table *merge;
819 struct route_node *rnode, *mrnode;
820
321c1bbb 821 merge = srcdest_table_init();
d62a17ae 822
80ef2e89
HS
823 for (int i = 0; tables[i]; i++) {
824 uint8_t algorithm = isis_route_table_algorithm(tables[i]);
825 for (rnode = route_top(tables[i]); rnode;
321c1bbb 826 rnode = srcdest_route_next(rnode)) {
26b0598f 827 struct isis_route_info *rinfo = rnode->info;
c951ee6e
RW
828 struct route_node *rnode_bck;
829
26b0598f 830 if (!rinfo)
3dace42d 831 continue;
26b0598f 832
321c1bbb
CF
833 struct prefix *prefix;
834 struct prefix_ipv6 *src_p;
835
836 srcdest_rnode_prefixes(rnode,
837 (const struct prefix **)&prefix,
838 (const struct prefix **)&src_p);
c951ee6e
RW
839
840 /* Link primary route to backup route. */
80ef2e89
HS
841 rnode_bck = srcdest_rnode_lookup(tables_backup[i],
842 prefix, src_p);
c951ee6e
RW
843 if (rnode_bck) {
844 rinfo->backup = rnode_bck->info;
7153c3ca 845 rinfo->sr_algo[algorithm].nexthops_backup =
bdaafbf8 846 rinfo->backup->nexthops;
c951ee6e
RW
847 UNSET_FLAG(rinfo->flag,
848 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
16fe8cff
RW
849 } else if (rinfo->backup) {
850 rinfo->backup = NULL;
7153c3ca
HS
851 rinfo->sr_algo[algorithm].nexthops_backup =
852 NULL;
16fe8cff
RW
853 UNSET_FLAG(rinfo->flag,
854 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
c951ee6e
RW
855 }
856
321c1bbb 857 mrnode = srcdest_rnode_get(merge, prefix, src_p);
26b0598f
CF
858 struct isis_route_info *mrinfo = mrnode->info;
859 if (mrinfo) {
3dace42d 860 route_unlock_node(mrnode);
7153c3ca
HS
861 set_merge_route_info_sr_algo(mrinfo, rinfo);
862
26b0598f
CF
863 if (CHECK_FLAG(mrinfo->flag,
864 ISIS_ROUTE_FLAG_ACTIVE)) {
865 /* Clear the ZEBRA_SYNCED flag on the
866 * L2 route when L1 wins, otherwise L2
867 * won't get reinstalled when L1
868 * disappears.
869 */
870 UNSET_FLAG(
871 rinfo->flag,
872 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
873 );
874 continue;
688ea1cb
EDP
875 } else if (CHECK_FLAG(rinfo->flag,
876 ISIS_ROUTE_FLAG_ACTIVE)) {
26b0598f
CF
877 /* Clear the ZEBRA_SYNCED flag on the L1
878 * route when L2 wins, otherwise L1
879 * won't get reinstalled when it
880 * reappears.
881 */
882 UNSET_FLAG(
883 mrinfo->flag,
884 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
885 );
688ea1cb
EDP
886 } else if (
887 CHECK_FLAG(
888 mrinfo->flag,
889 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
890 continue;
26b0598f 891 }
224eadd9
EK
892 } else {
893 mrnode->info = rnode->info;
3dace42d 894 }
3dace42d 895 }
d62a17ae 896 }
897
c951ee6e 898 _isis_route_verify_table(area, merge, NULL, tables);
d62a17ae 899 route_table_finish(merge);
fac1f7cc 900}
901
d62a17ae 902void isis_route_invalidate_table(struct isis_area *area,
903 struct route_table *table)
3f045a08 904{
d62a17ae 905 struct route_node *rode;
906 struct isis_route_info *rinfo;
7153c3ca 907 uint8_t algorithm = isis_route_table_algorithm(table);
321c1bbb 908 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
d62a17ae 909 if (rode->info == NULL)
910 continue;
911 rinfo = rode->info;
912
c951ee6e
RW
913 if (rinfo->backup) {
914 rinfo->backup = NULL;
7153c3ca 915 rinfo->sr_algo[algorithm].nexthops_backup = NULL;
c951ee6e
RW
916 /*
917 * For now, always force routes that have backup
918 * nexthops to be reinstalled.
919 */
920 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
921 }
d62a17ae 922 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
923 }
3f045a08 924}
694fa867
LS
925
926void isis_route_switchover_nexthop(struct isis_area *area,
927 struct route_table *table, int family,
928 union g_addr *nexthop_addr,
929 ifindex_t ifindex)
930{
931 const char *ifname = NULL, *vrfname = NULL;
932 struct isis_route_info *rinfo;
933 struct prefix_ipv6 *src_p;
934 struct route_node *rnode;
935 vrf_id_t vrf_id;
936 struct prefix *prefix;
937
938 if (IS_DEBUG_EVENTS) {
939 if (area && area->isis) {
940 vrf_id = area->isis->vrf_id;
941 vrfname = vrf_id_to_name(vrf_id);
942 ifname = ifindex2ifname(ifindex, vrf_id);
943 }
944 zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
945 __func__, family2str(family), vrfname ? vrfname : "",
946 ifname ? ifname : "");
947 }
948
949 for (rnode = route_top(table); rnode;
950 rnode = srcdest_route_next(rnode)) {
951 if (!rnode->info)
952 continue;
953 rinfo = rnode->info;
954
955 if (!rinfo->backup)
956 continue;
957
958 if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
959 ifindex))
960 continue;
961
962 srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
963 (const struct prefix **)&src_p);
964
965 /* Switchover route. */
8a65b22d 966 isis_route_remove_previous_sid(area, prefix, rinfo);
694fa867
LS
967 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
968 isis_route_update(area, prefix, src_p, rinfo->backup);
969
970 isis_route_info_delete(rinfo);
971
972 rnode->info = NULL;
973 route_unlock_node(rnode);
974 }
975}