DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
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,
(struct isis_area * area, struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info);
-static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
- ifindex_t ifindex)
+static struct mpls_label_stack *
+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;
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)
{
XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
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,
union g_addr *ip, ifindex_t ifindex)
{
rinfo->cost = cost;
rinfo->depth = depth;
- rinfo->sr = *sr;
- rinfo->sr.nexthops = rinfo->nexthops;
- rinfo->sr.nexthops_backup =
+ rinfo->sr_algo[sr->algorithm] = *sr;
+ rinfo->sr_algo[sr->algorithm].nexthops = rinfo->nexthops;
+ rinfo->sr_algo[sr->algorithm].nexthops_backup =
rinfo->backup ? rinfo->backup->nexthops : NULL;
return rinfo;
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) {
route_info->nexthops->del =
(void (*)(void *))isis_nexthop_delete;
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,
struct isis_sr_psid_info *old)
{
return 0;
}
- if (!isis_sr_psid_info_same(&new->sr, &old->sr)) {
- if (buf)
- snprintf(buf, buf_size, "SR input label");
- return 0;
+ 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)
+ 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;
+ }
}
if (new->nexthops->count != old->nexthops->count) {
zlog_debug(
"ISIS-Rte (%s): route changed: %pFX, change: %s",
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);
route_info = rinfo_new;
UNSET_FLAG(route_info->flag,
* Explicitly uninstall previous Prefix-SID label if it has
* changed or was removed.
*/
- if (route_info->sr_previous.present &&
- (!route_info->sr.present ||
- route_info->sr_previous.label != route_info->sr.label))
- isis_zebra_prefix_sid_uninstall(area, prefix, route_info,
- &route_info->sr_previous);
+ for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+ if (route_info->sr_algo_previous[i].present &&
+ (!route_info->sr_algo[i].present ||
+ route_info->sr_algo_previous[i].label !=
+ 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,
/* Install route. */
isis_zebra_route_add_route(area->isis, prefix, src_p,
route_info);
- /* Install/reinstall Prefix-SID label. */
- if (route_info->sr.present)
- isis_zebra_prefix_sid_install(area, prefix,
- &route_info->sr);
+
+ 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,
+ &sr_algo);
+
+ hook_call(isis_route_update_hook, area, prefix,
+ route_info);
+ }
hook_call(isis_route_update_hook, area, prefix, route_info);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
} else {
/* Uninstall Prefix-SID label. */
- if (route_info->sr.present)
- isis_zebra_prefix_sid_uninstall(
- area, prefix, route_info, &route_info->sr);
+ for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+ if (route_info->sr_algo[i].present)
+ isis_zebra_prefix_sid_uninstall(
+ area, prefix, route_info,
+ &route_info->sr_algo[i]);
+
/* Uninstall route. */
isis_zebra_route_del_route(area->isis, prefix, src_p,
route_info);
#ifdef EXTREME_DEBUG
char buff[SRCDEST2STR_BUFFER];
#endif /* EXTREME_DEBUG */
+ uint8_t algorithm = isis_route_table_algorithm(table);
for (rnode = route_top(table); rnode;
rnode = srcdest_route_next(rnode)) {
src_p);
if (rnode_bck) {
rinfo->backup = rnode_bck->info;
- rinfo->sr.nexthops_backup =
+ rinfo->sr_algo[algorithm].nexthops_backup =
rinfo->backup->nexthops;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else if (rinfo->backup) {
rinfo->backup = NULL;
- rinfo->sr.nexthops_backup = NULL;
+ rinfo->sr_algo[algorithm].nexthops_backup =
+ NULL;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
merge = srcdest_table_init();
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;
rnode = srcdest_route_next(rnode)) {
struct isis_route_info *rinfo = rnode->info;
tables_backup[level - 1], prefix, src_p);
if (rnode_bck) {
rinfo->backup = rnode_bck->info;
- rinfo->sr.nexthops_backup =
+ rinfo->sr_algo[algorithm].nexthops_backup =
rinfo->backup->nexthops;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else if (rinfo->backup) {
rinfo->backup = NULL;
- rinfo->sr.nexthops_backup = NULL;
+ rinfo->sr_algo[algorithm].nexthops_backup =
+ NULL;
UNSET_FLAG(rinfo->flag,
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
struct isis_route_info *mrinfo = mrnode->info;
if (mrinfo) {
route_unlock_node(mrnode);
+ set_merge_route_info_sr_algo(mrinfo, rinfo);
+
if (CHECK_FLAG(mrinfo->flag,
ISIS_ROUTE_FLAG_ACTIVE)) {
/* Clear the ZEBRA_SYNCED flag on the
{
struct route_node *rode;
struct isis_route_info *rinfo;
+ uint8_t algorithm = isis_route_table_algorithm(table);
for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
if (rode->info == NULL)
continue;
if (rinfo->backup) {
rinfo->backup = NULL;
- rinfo->sr.nexthops_backup = NULL;
+ rinfo->sr_algo[algorithm].nexthops_backup = NULL;
/*
* For now, always force routes that have backup
* nexthops to be reinstalled.
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
tree->route_table = srcdest_table_init();
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->info = isis_route_table_info_alloc(algorithm);
tree->route_table_backup->cleanup = isis_route_node_cleanup;
tree->area = area;
tree->lspdb = lspdb;
list_delete(&spftree->sadj_list);
isis_vertex_queue_free(&spftree->tents);
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_backup);
spftree->route_table = NULL;
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);
/* Delete backup routes. */
+
+ backup_info = tree->route_table_backup->info;
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->info =
+ isis_route_table_info_alloc(tree->algorithm);
tree->route_table_backup->cleanup = isis_route_node_cleanup;
}
if (nexthop->sr.present) {
snprintf(buf_sid, sizeof(buf_sid), "%u",
nexthop->sr.sid.value);
- sr_op2str(buf_lblop, sizeof(buf_lblop),
- rinfo->sr.label, nexthop->sr.label);
+ sr_op2str(
+ buf_lblop, sizeof(buf_lblop),
+ rinfo->sr_algo[SR_ALGORITHM_SPF].label,
+ nexthop->sr.label);
} else {
strlcpy(buf_sid, "-", sizeof(buf_sid));
strlcpy(buf_lblop, "-", sizeof(buf_lblop));
char buf_sid[BUFSIZ] = {};
char buf_lblop[BUFSIZ] = {};
- if (rinfo->sr.present) {
+ if (rinfo->sr_algo[SR_ALGORITHM_SPF].present) {
snprintf(buf_sid, sizeof(buf_sid), "%u",
- rinfo->sr.sid.value);
- sr_op2str(buf_lblop, sizeof(buf_lblop),
- rinfo->sr.label,
- MPLS_LABEL_IMPLICIT_NULL);
+ rinfo->sr_algo[SR_ALGORITHM_SPF]
+ .sid.value);
+ sr_op2str(
+ buf_lblop, sizeof(buf_lblop),
+ rinfo->sr_algo[SR_ALGORITHM_SPF].label,
+ MPLS_LABEL_IMPLICIT_NULL);
} else {
strlcpy(buf_sid, "-", sizeof(buf_sid));
strlcpy(buf_lblop, "-", sizeof(buf_lblop));