isisd: update struct isis_route_info has multiple sr info by algorithm

Before this commit, there was only one sr psid info
included in route_info.

In fact, in RFC8667, Algorithm ID, which is a property of
Prefix-SID, has 8 bits of information. That is, each Prefix
can hold up to 256 Prefix-SIDs. This commit implements it.
The previously implemented single Prefix-SID will be
continued as Algorithm 0.

Signed-off-by: Hiroki Shirokura <hiroki.shirokura@linecorp.com>
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
This commit is contained in:
Hiroki Shirokura 2021-12-12 09:20:21 +00:00 committed by Louis Scalbert
parent bdaafbf834
commit 7153c3cabf
3 changed files with 208 additions and 36 deletions

View File

@ -39,6 +39,8 @@
DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop"); DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info"); DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_TABLE_INFO, "ISIS route table info");
DEFINE_HOOK(isis_route_update_hook, DEFINE_HOOK(isis_route_update_hook,
(struct isis_area * area, struct prefix *prefix, (struct isis_area * area, struct prefix *prefix,
@ -51,8 +53,25 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
struct prefix_ipv6 *src_p, struct prefix_ipv6 *src_p,
struct isis_route_info *route_info); struct isis_route_info *route_info);
static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip, static struct mpls_label_stack *
ifindex_t ifindex) label_stack_dup(const struct mpls_label_stack *const orig)
{
struct mpls_label_stack *copy;
int array_size;
if (orig == NULL)
return NULL;
array_size = orig->num_labels * sizeof(mpls_label_t);
copy = XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
sizeof(struct mpls_label_stack) + array_size);
copy->num_labels = orig->num_labels;
memcpy(copy->label, orig->label, array_size);
return copy;
}
static struct isis_nexthop *
isis_nexthop_create(int family, const union g_addr *const ip, ifindex_t ifindex)
{ {
struct isis_nexthop *nexthop; struct isis_nexthop *nexthop;
@ -65,12 +84,40 @@ static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
return nexthop; return nexthop;
} }
static struct isis_nexthop *
isis_nexthop_dup(const struct isis_nexthop *const orig)
{
struct isis_nexthop *nexthop;
nexthop = isis_nexthop_create(orig->family, &orig->ip, orig->ifindex);
memcpy(nexthop->sysid, orig->sysid, ISIS_SYS_ID_LEN);
nexthop->sr = orig->sr;
nexthop->label_stack = label_stack_dup(orig->label_stack);
return nexthop;
}
void isis_nexthop_delete(struct isis_nexthop *nexthop) void isis_nexthop_delete(struct isis_nexthop *nexthop)
{ {
XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack); XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
XFREE(MTYPE_ISIS_NEXTHOP, nexthop); XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
} }
static struct list *isis_nexthop_list_dup(const struct list *orig)
{
struct list *copy;
struct listnode *node;
struct isis_nexthop *nh;
struct isis_nexthop *nhcopy;
copy = list_new();
for (ALL_LIST_ELEMENTS_RO(orig, node, nh)) {
nhcopy = isis_nexthop_dup(nh);
listnode_add(copy, nhcopy);
}
return copy;
}
static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family, static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
union g_addr *ip, ifindex_t ifindex) union g_addr *ip, ifindex_t ifindex)
{ {
@ -238,9 +285,9 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
rinfo->cost = cost; rinfo->cost = cost;
rinfo->depth = depth; rinfo->depth = depth;
rinfo->sr = *sr; rinfo->sr_algo[sr->algorithm] = *sr;
rinfo->sr.nexthops = rinfo->nexthops; rinfo->sr_algo[sr->algorithm].nexthops = rinfo->nexthops;
rinfo->sr.nexthops_backup = rinfo->sr_algo[sr->algorithm].nexthops_backup =
rinfo->backup ? rinfo->backup->nexthops : NULL; rinfo->backup ? rinfo->backup->nexthops : NULL;
return rinfo; return rinfo;
@ -248,6 +295,18 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
static void isis_route_info_delete(struct isis_route_info *route_info) static void isis_route_info_delete(struct isis_route_info *route_info)
{ {
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
if (!route_info->sr_algo[i].present)
continue;
if (route_info->sr_algo[i].nexthops == route_info->nexthops)
continue;
route_info->sr_algo[i].nexthops->del =
(void (*)(void *))isis_nexthop_delete;
list_delete(&route_info->sr_algo[i].nexthops);
}
if (route_info->nexthops) { if (route_info->nexthops) {
route_info->nexthops->del = route_info->nexthops->del =
(void (*)(void *))isis_nexthop_delete; (void (*)(void *))isis_nexthop_delete;
@ -263,6 +322,27 @@ void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
isis_route_info_delete(node->info); isis_route_info_delete(node->info);
} }
struct isis_route_table_info *isis_route_table_info_alloc(uint8_t algorithm)
{
struct isis_route_table_info *info;
info = XCALLOC(MTYPE_ISIS_ROUTE_TABLE_INFO, sizeof(*info));
info->algorithm = algorithm;
return info;
}
void isis_route_table_info_free(void *info)
{
XFREE(MTYPE_ISIS_ROUTE_TABLE_INFO, info);
}
uint8_t isis_route_table_algorithm(const struct route_table *table)
{
const struct isis_route_table_info *info = table->info;
return info ? info->algorithm : 0;
}
static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new, static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
struct isis_sr_psid_info *old) struct isis_sr_psid_info *old)
{ {
@ -319,11 +399,23 @@ static int isis_route_info_same(struct isis_route_info *new,
return 0; return 0;
} }
if (!isis_sr_psid_info_same(&new->sr, &old->sr)) { for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
struct isis_sr_psid_info new_sr_algo;
struct isis_sr_psid_info old_sr_algo;
new_sr_algo = new->sr_algo[i];
old_sr_algo = old->sr_algo[i];
if (!isis_sr_psid_info_same(&new_sr_algo, &old_sr_algo)) {
if (buf) if (buf)
snprintf(buf, buf_size, "SR input label"); snprintf(
buf, buf_size,
"SR input label algo-%u (old: %s, new: %s)",
i, old_sr_algo.present ? "yes" : "no",
new_sr_algo.present ? "yes" : "no");
return 0; return 0;
} }
}
if (new->nexthops->count != old->nexthops->count) { if (new->nexthops->count != old->nexthops->count) {
if (buf) if (buf)
@ -411,7 +503,9 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
zlog_debug( zlog_debug(
"ISIS-Rte (%s): route changed: %pFX, change: %s", "ISIS-Rte (%s): route changed: %pFX, change: %s",
area->area_tag, prefix, change_buf); area->area_tag, prefix, change_buf);
rinfo_new->sr_previous = rinfo_old->sr; for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
rinfo_new->sr_algo_previous[i] =
rinfo_old->sr_algo[i];
isis_route_info_delete(rinfo_old); isis_route_info_delete(rinfo_old);
route_info = rinfo_new; route_info = rinfo_new;
UNSET_FLAG(route_info->flag, UNSET_FLAG(route_info->flag,
@ -467,11 +561,42 @@ static void isis_route_remove_previous_sid(struct isis_area *area,
* Explicitly uninstall previous Prefix-SID label if it has * Explicitly uninstall previous Prefix-SID label if it has
* changed or was removed. * changed or was removed.
*/ */
if (route_info->sr_previous.present && for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
(!route_info->sr.present || if (route_info->sr_algo_previous[i].present &&
route_info->sr_previous.label != route_info->sr.label)) (!route_info->sr_algo[i].present ||
isis_zebra_prefix_sid_uninstall(area, prefix, route_info, route_info->sr_algo_previous[i].label !=
&route_info->sr_previous); route_info->sr_algo[i].label))
isis_zebra_prefix_sid_uninstall(
area, prefix, route_info,
&route_info->sr_algo_previous[i]);
}
}
static void set_merge_route_info_sr_algo(struct isis_route_info *mrinfo,
struct isis_route_info *rinfo)
{
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
if (rinfo->sr_algo[i].present) {
assert(i == rinfo->sr_algo[i].algorithm);
assert(rinfo->nexthops);
assert(rinfo->backup ? rinfo->backup->nexthops != NULL
: true);
if (mrinfo->sr_algo[i].nexthops != NULL &&
mrinfo->sr_algo[i].nexthops != mrinfo->nexthops) {
mrinfo->sr_algo[i].nexthops->del =
(void (*)(void *))isis_nexthop_delete;
list_delete(&mrinfo->sr_algo[i].nexthops);
}
mrinfo->sr_algo[i] = rinfo->sr_algo[i];
mrinfo->sr_algo[i].nexthops = isis_nexthop_list_dup(
rinfo->sr_algo[i].nexthops);
}
}
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
UNSET_FLAG(mrinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} }
static void isis_route_update(struct isis_area *area, struct prefix *prefix, static void isis_route_update(struct isis_area *area, struct prefix *prefix,
@ -490,10 +615,22 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
/* Install route. */ /* Install route. */
isis_zebra_route_add_route(area->isis, prefix, src_p, isis_zebra_route_add_route(area->isis, prefix, src_p,
route_info); route_info);
/* Install/reinstall Prefix-SID label. */
if (route_info->sr.present) for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
struct isis_sr_psid_info sr_algo;
sr_algo = route_info->sr_algo[i];
/*
* Install/reinstall Prefix-SID label.
*/
if (sr_algo.present)
isis_zebra_prefix_sid_install(area, prefix, isis_zebra_prefix_sid_install(area, prefix,
&route_info->sr); &sr_algo);
hook_call(isis_route_update_hook, area, prefix,
route_info);
}
hook_call(isis_route_update_hook, area, prefix, route_info); hook_call(isis_route_update_hook, area, prefix, route_info);
@ -501,9 +638,12 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
} else { } else {
/* Uninstall Prefix-SID label. */ /* Uninstall Prefix-SID label. */
if (route_info->sr.present) for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
if (route_info->sr_algo[i].present)
isis_zebra_prefix_sid_uninstall( isis_zebra_prefix_sid_uninstall(
area, prefix, route_info, &route_info->sr); area, prefix, route_info,
&route_info->sr_algo[i]);
/* Uninstall route. */ /* Uninstall route. */
isis_zebra_route_del_route(area->isis, prefix, src_p, isis_zebra_route_del_route(area->isis, prefix, src_p,
route_info); route_info);
@ -523,6 +663,7 @@ static void _isis_route_verify_table(struct isis_area *area,
#ifdef EXTREME_DEBUG #ifdef EXTREME_DEBUG
char buff[SRCDEST2STR_BUFFER]; char buff[SRCDEST2STR_BUFFER];
#endif /* EXTREME_DEBUG */ #endif /* EXTREME_DEBUG */
uint8_t algorithm = isis_route_table_algorithm(table);
for (rnode = route_top(table); rnode; for (rnode = route_top(table); rnode;
rnode = srcdest_route_next(rnode)) { rnode = srcdest_route_next(rnode)) {
@ -545,13 +686,14 @@ static void _isis_route_verify_table(struct isis_area *area,
src_p); src_p);
if (rnode_bck) { if (rnode_bck) {
rinfo->backup = rnode_bck->info; rinfo->backup = rnode_bck->info;
rinfo->sr.nexthops_backup = rinfo->sr_algo[algorithm].nexthops_backup =
rinfo->backup->nexthops; rinfo->backup->nexthops;
UNSET_FLAG(rinfo->flag, UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED); ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else if (rinfo->backup) { } else if (rinfo->backup) {
rinfo->backup = NULL; rinfo->backup = NULL;
rinfo->sr.nexthops_backup = NULL; rinfo->sr_algo[algorithm].nexthops_backup =
NULL;
UNSET_FLAG(rinfo->flag, UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED); ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} }
@ -645,6 +787,8 @@ void isis_route_verify_merge(struct isis_area *area,
merge = srcdest_table_init(); merge = srcdest_table_init();
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
uint8_t algorithm =
isis_route_table_algorithm(tables[level - 1]);
for (rnode = route_top(tables[level - 1]); rnode; for (rnode = route_top(tables[level - 1]); rnode;
rnode = srcdest_route_next(rnode)) { rnode = srcdest_route_next(rnode)) {
struct isis_route_info *rinfo = rnode->info; struct isis_route_info *rinfo = rnode->info;
@ -665,13 +809,14 @@ void isis_route_verify_merge(struct isis_area *area,
tables_backup[level - 1], prefix, src_p); tables_backup[level - 1], prefix, src_p);
if (rnode_bck) { if (rnode_bck) {
rinfo->backup = rnode_bck->info; rinfo->backup = rnode_bck->info;
rinfo->sr.nexthops_backup = rinfo->sr_algo[algorithm].nexthops_backup =
rinfo->backup->nexthops; rinfo->backup->nexthops;
UNSET_FLAG(rinfo->flag, UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED); ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else if (rinfo->backup) { } else if (rinfo->backup) {
rinfo->backup = NULL; rinfo->backup = NULL;
rinfo->sr.nexthops_backup = NULL; rinfo->sr_algo[algorithm].nexthops_backup =
NULL;
UNSET_FLAG(rinfo->flag, UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED); ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} }
@ -680,6 +825,8 @@ void isis_route_verify_merge(struct isis_area *area,
struct isis_route_info *mrinfo = mrnode->info; struct isis_route_info *mrinfo = mrnode->info;
if (mrinfo) { if (mrinfo) {
route_unlock_node(mrnode); route_unlock_node(mrnode);
set_merge_route_info_sr_algo(mrinfo, rinfo);
if (CHECK_FLAG(mrinfo->flag, if (CHECK_FLAG(mrinfo->flag,
ISIS_ROUTE_FLAG_ACTIVE)) { ISIS_ROUTE_FLAG_ACTIVE)) {
/* Clear the ZEBRA_SYNCED flag on the /* Clear the ZEBRA_SYNCED flag on the
@ -723,6 +870,7 @@ void isis_route_invalidate_table(struct isis_area *area,
{ {
struct route_node *rode; struct route_node *rode;
struct isis_route_info *rinfo; struct isis_route_info *rinfo;
uint8_t algorithm = isis_route_table_algorithm(table);
for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) { for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
if (rode->info == NULL) if (rode->info == NULL)
continue; continue;
@ -730,7 +878,7 @@ void isis_route_invalidate_table(struct isis_area *area,
if (rinfo->backup) { if (rinfo->backup) {
rinfo->backup = NULL; rinfo->backup = NULL;
rinfo->sr.nexthops_backup = NULL; rinfo->sr_algo[algorithm].nexthops_backup = NULL;
/* /*
* For now, always force routes that have backup * For now, always force routes that have backup
* nexthops to be reinstalled. * nexthops to be reinstalled.

View File

@ -30,12 +30,16 @@ struct isis_route_info {
uint8_t flag; uint8_t flag;
uint32_t cost; uint32_t cost;
uint32_t depth; uint32_t depth;
struct isis_sr_psid_info sr; struct isis_sr_psid_info sr_algo[SR_ALGORITHM_COUNT];
struct isis_sr_psid_info sr_previous; struct isis_sr_psid_info sr_algo_previous[SR_ALGORITHM_COUNT];
struct list *nexthops; struct list *nexthops;
struct isis_route_info *backup; struct isis_route_info *backup;
}; };
struct isis_route_table_info {
uint8_t algorithm;
};
DECLARE_HOOK(isis_route_update_hook, DECLARE_HOOK(isis_route_update_hook,
(struct isis_area * area, struct prefix *prefix, (struct isis_area * area, struct prefix *prefix,
struct isis_route_info *route_info), struct isis_route_info *route_info),
@ -73,9 +77,14 @@ void isis_route_invalidate_table(struct isis_area *area,
void isis_route_node_cleanup(struct route_table *table, void isis_route_node_cleanup(struct route_table *table,
struct route_node *node); struct route_node *node);
void isis_route_switchover_nexthop(struct isis_area *area, void isis_route_switchover_nexthop(struct isis_area *area,
struct route_table *table, int family, struct route_table *table, int family,
union g_addr *nexthop_addr, union g_addr *nexthop_addr,
ifindex_t ifindex); ifindex_t ifindex);
struct isis_route_table_info *isis_route_table_info_alloc(uint8_t algorithm);
void isis_route_table_info_free(void *info);
uint8_t isis_route_table_algorithm(const struct route_table *table);
#endif /* _ZEBRA_ISIS_ROUTE_H */ #endif /* _ZEBRA_ISIS_ROUTE_H */

View File

@ -335,7 +335,9 @@ isis_spftree_new(struct isis_area *area, struct lspdb_head *lspdb,
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false); isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
tree->route_table = srcdest_table_init(); tree->route_table = srcdest_table_init();
tree->route_table->cleanup = isis_route_node_cleanup; tree->route_table->cleanup = isis_route_node_cleanup;
tree->route_table->info = isis_route_table_info_alloc(algorithm);
tree->route_table_backup = srcdest_table_init(); tree->route_table_backup = srcdest_table_init();
tree->route_table_backup->info = isis_route_table_info_alloc(algorithm);
tree->route_table_backup->cleanup = isis_route_node_cleanup; tree->route_table_backup->cleanup = isis_route_node_cleanup;
tree->area = area; tree->area = area;
tree->lspdb = lspdb; tree->lspdb = lspdb;
@ -380,6 +382,8 @@ void isis_spftree_del(struct isis_spftree *spftree)
list_delete(&spftree->sadj_list); list_delete(&spftree->sadj_list);
isis_vertex_queue_free(&spftree->tents); isis_vertex_queue_free(&spftree->tents);
isis_vertex_queue_free(&spftree->paths); isis_vertex_queue_free(&spftree->paths);
isis_route_table_info_free(spftree->route_table->info);
isis_route_table_info_free(spftree->route_table_backup->info);
route_table_finish(spftree->route_table); route_table_finish(spftree->route_table);
route_table_finish(spftree->route_table_backup); route_table_finish(spftree->route_table_backup);
spftree->route_table = NULL; spftree->route_table = NULL;
@ -1838,11 +1842,18 @@ void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
void isis_spf_invalidate_routes(struct isis_spftree *tree) void isis_spf_invalidate_routes(struct isis_spftree *tree)
{ {
struct isis_route_table_info *backup_info;
isis_route_invalidate_table(tree->area, tree->route_table); isis_route_invalidate_table(tree->area, tree->route_table);
/* Delete backup routes. */ /* Delete backup routes. */
backup_info = tree->route_table_backup->info;
route_table_finish(tree->route_table_backup); route_table_finish(tree->route_table_backup);
isis_route_table_info_free(backup_info);
tree->route_table_backup = srcdest_table_init(); tree->route_table_backup = srcdest_table_init();
tree->route_table_backup->info =
isis_route_table_info_alloc(tree->algorithm);
tree->route_table_backup->cleanup = isis_route_node_cleanup; tree->route_table_backup->cleanup = isis_route_node_cleanup;
} }
@ -2242,8 +2253,10 @@ static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
if (nexthop->sr.present) { if (nexthop->sr.present) {
snprintf(buf_sid, sizeof(buf_sid), "%u", snprintf(buf_sid, sizeof(buf_sid), "%u",
nexthop->sr.sid.value); nexthop->sr.sid.value);
sr_op2str(buf_lblop, sizeof(buf_lblop), sr_op2str(
rinfo->sr.label, nexthop->sr.label); buf_lblop, sizeof(buf_lblop),
rinfo->sr_algo[SR_ALGORITHM_SPF].label,
nexthop->sr.label);
} else { } else {
strlcpy(buf_sid, "-", sizeof(buf_sid)); strlcpy(buf_sid, "-", sizeof(buf_sid));
strlcpy(buf_lblop, "-", sizeof(buf_lblop)); strlcpy(buf_lblop, "-", sizeof(buf_lblop));
@ -2298,11 +2311,13 @@ static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
char buf_sid[BUFSIZ] = {}; char buf_sid[BUFSIZ] = {};
char buf_lblop[BUFSIZ] = {}; char buf_lblop[BUFSIZ] = {};
if (rinfo->sr.present) { if (rinfo->sr_algo[SR_ALGORITHM_SPF].present) {
snprintf(buf_sid, sizeof(buf_sid), "%u", snprintf(buf_sid, sizeof(buf_sid), "%u",
rinfo->sr.sid.value); rinfo->sr_algo[SR_ALGORITHM_SPF]
sr_op2str(buf_lblop, sizeof(buf_lblop), .sid.value);
rinfo->sr.label, sr_op2str(
buf_lblop, sizeof(buf_lblop),
rinfo->sr_algo[SR_ALGORITHM_SPF].label,
MPLS_LABEL_IMPLICIT_NULL); MPLS_LABEL_IMPLICIT_NULL);
} else { } else {
strlcpy(buf_sid, "-", sizeof(buf_sid)); strlcpy(buf_sid, "-", sizeof(buf_sid));