summaryrefslogtreecommitdiff
path: root/isisd/isis_route.c
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2020-09-20 02:39:28 -0300
committerRenato Westphal <renato@opensourcerouting.org>2020-10-23 10:31:39 -0300
commitd47d6089e06c2c6b9f0f5ae4518f0e07abdca1af (patch)
tree78b3bbe7a05e5e76e551b377d3ece5b82641b93a /isisd/isis_route.c
parentd4fcd8bd82b232a467f5063268683a5dd7d52cd2 (diff)
isisd: refactor handling of SR Prefix-SIDs
Embed Prefix-SID information inside SPF data structures so that Prefix-SIDs can be installed together with their associated routes at the end of the SPF algorithm. This is different from the current implementation where Prefix-SIDs are parsed and processed separately, which is vastly suboptimal. Advantages of the new code: * No need to parse the LSPDB an additional time to detect and process SR-related changes; * Routes are installed with their Prefix-SID labels in the same ZAPI message. This can prevent packet dropping for a few milliseconds after each SPF run if there are BGP-labeled routes (e.g. L3VPN) that recurse on IGP labeled routes; * Much easier to support Anycast-SIDs, as the SPF code will naturally figure out the best nexthops and use only them (that can't be done in any reasonable way if the Prefix-SID Sub-TVLs are processed separately); * Less code to maintain and reduced memory footprint; The "show isis segment-routing prefix-sids" command was removed as it doesn't make sense anymore now that "show isis route" exists. Prefix-SIDs are a property of routes, so what was done was to extend the "show isis route" command with a new "prefix-sid" option that changes the output table to show the Prefix-SID information associated to each route. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'isisd/isis_route.c')
-rw-r--r--isisd/isis_route.c106
1 files changed, 81 insertions, 25 deletions
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index 7e8c877bd0..d664a6f896 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -71,7 +71,6 @@ static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
nexthop->family = family;
nexthop->ifindex = ifindex;
nexthop->ip = *ip;
- isis_sr_nexthop_reset(&nexthop->sr);
return nexthop;
}
@@ -117,7 +116,7 @@ static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
}
void adjinfo2nexthop(int family, struct list *nexthops,
- struct isis_adjacency *adj,
+ struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
struct mpls_label_stack *label_stack)
{
struct isis_nexthop *nh;
@@ -134,6 +133,8 @@ void adjinfo2nexthop(int family, struct list *nexthops,
AF_INET, &ip,
adj->circuit->interface->ifindex);
memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
+ if (sr)
+ nh->sr = *sr;
nh->label_stack = label_stack;
listnode_add(nexthops, nh);
break;
@@ -150,6 +151,8 @@ void adjinfo2nexthop(int family, struct list *nexthops,
AF_INET6, &ip,
adj->circuit->interface->ifindex);
memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
+ if (sr)
+ nh->sr = *sr;
nh->label_stack = label_stack;
listnode_add(nexthops, nh);
break;
@@ -165,22 +168,22 @@ void adjinfo2nexthop(int family, struct list *nexthops,
static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
const uint8_t *sysid,
+ struct isis_sr_psid_info *sr,
struct mpls_label_stack *label_stack)
{
struct isis_nexthop *nh;
nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
memcpy(nh->sysid, sysid, sizeof(nh->sysid));
- isis_sr_nexthop_reset(&nh->sr);
+ nh->sr = *sr;
nh->label_stack = label_stack;
listnode_add(rinfo->nexthops, nh);
}
-static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
- struct prefix_ipv6 *src_p,
- uint32_t cost,
- uint32_t depth,
- struct list *adjacencies)
+static struct isis_route_info *
+isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
+ uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
+ struct list *adjacencies)
{
struct isis_route_info *rinfo;
struct isis_vertex_adj *vadj;
@@ -192,6 +195,7 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
struct isis_spf_adj *sadj = vadj->sadj;
struct isis_adjacency *adj = sadj->adj;
+ struct isis_sr_psid_info *sr = &vadj->sr;
struct mpls_label_stack *label_stack = vadj->label_stack;
/*
@@ -199,7 +203,7 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
* environment.
*/
if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
- isis_route_add_dummy_nexthops(rinfo, sadj->id,
+ isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
label_stack);
continue;
}
@@ -227,12 +231,13 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
prefix->family);
exit(1);
}
- adjinfo2nexthop(prefix->family, rinfo->nexthops, adj,
+ adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
label_stack);
}
rinfo->cost = cost;
rinfo->depth = depth;
+ rinfo->sr = *sr;
return rinfo;
}
@@ -254,12 +259,28 @@ void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
isis_route_info_delete(node->info);
}
+static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
+ struct isis_sr_psid_info *old)
+{
+ if (new->present != old->present)
+ return false;
+
+ if (new->label != old->label)
+ return false;
+
+ if (new->sid.flags != old->sid.flags
+ || new->sid.value != old->sid.value)
+ return false;
+
+ return true;
+}
+
static int isis_route_info_same(struct isis_route_info *new,
struct isis_route_info *old, char *buf,
size_t buf_size)
{
struct listnode *node;
- struct isis_nexthop *nexthop;
+ struct isis_nexthop *new_nh, *old_nh;
if (new->cost != old->cost) {
if (buf)
@@ -275,6 +296,12 @@ static int isis_route_info_same(struct isis_route_info *new,
return 0;
}
+ if (!isis_sr_psid_info_same(&new->sr, &old->sr)) {
+ if (buf)
+ snprintf(buf, buf_size, "SR input label");
+ return 0;
+ }
+
if (new->nexthops->count != old->nexthops->count) {
if (buf)
snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
@@ -282,14 +309,20 @@ static int isis_route_info_same(struct isis_route_info *new,
return 0;
}
- for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop)) {
- if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
- nexthop->ifindex)) {
+ for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
+ old_nh = nexthoplookup(old->nexthops, new_nh->family,
+ &new_nh->ip, new_nh->ifindex);
+ if (!old_nh) {
if (buf)
snprintf(buf, buf_size,
"new nhop"); /* TODO: print nhop */
return 0;
}
+ if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
+ if (buf)
+ snprintf(buf, buf_size, "nhop SR label");
+ return 0;
+ }
}
/* only the resync flag needs to be checked */
@@ -303,13 +336,11 @@ static int isis_route_info_same(struct isis_route_info *new,
return 1;
}
-struct isis_route_info *isis_route_create(struct prefix *prefix,
- struct prefix_ipv6 *src_p,
- uint32_t cost,
- uint32_t depth,
- struct list *adjacencies,
- struct isis_area *area,
- struct route_table *table)
+struct isis_route_info *
+isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
+ uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
+ struct list *adjacencies, struct isis_area *area,
+ struct route_table *table)
{
struct route_node *route_node;
struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
@@ -318,8 +349,8 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
if (!table)
return NULL;
- rinfo_new = isis_route_info_new(prefix, src_p, cost,
- depth, adjacencies);
+ rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
+ adjacencies);
route_node = srcdest_rnode_get(table, prefix, src_p);
rinfo_old = route_node->info;
@@ -351,6 +382,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
zlog_debug(
"ISIS-Rte (%s): route changed: %pFX, change: %s",
area->area_tag, prefix, change_buf);
+ rinfo_new->sr_previous = rinfo_old->sr;
isis_route_info_delete(rinfo_old);
route_info = rinfo_new;
UNSET_FLAG(route_info->flag,
@@ -406,7 +438,25 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
- isis_zebra_route_add_route(area->isis, prefix, src_p, route_info);
+ /*
+ * 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);
+
+ /* 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,
+ &route_info->sr);
hook_call(isis_route_update_hook, area, prefix, route_info);
SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
@@ -415,7 +465,13 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
- isis_zebra_route_del_route(area->isis, prefix, src_p, route_info);
+ /* Uninstall Prefix-SID label. */
+ if (route_info->sr.present)
+ isis_zebra_prefix_sid_uninstall(
+ area, prefix, route_info, &route_info->sr);
+ /* Uninstall route. */
+ isis_zebra_route_del_route(area->isis, prefix, src_p,
+ route_info);
hook_call(isis_route_update_hook, area, prefix, route_info);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);