Skip to content

Commit

Permalink
isisd: refactor handling of SR Prefix-SIDs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
rwestphal committed Oct 23, 2020
1 parent d4fcd8b commit d47d608
Show file tree
Hide file tree
Showing 15 changed files with 958 additions and 1,936 deletions.
4 changes: 2 additions & 2 deletions doc/user/isisd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ Showing ISIS information
Show topology IS-IS paths to Intermediate Systems, globally, in area
(level-1) or domain (level-2).

.. index:: show isis route [level-1|level-2] [backup]
.. clicmd:: show isis route [level-1|level-2] [backup]
.. index:: show isis route [level-1|level-2] [prefix-sid|backup]
.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup]

Show the ISIS routing table, as determined by the most recent SPF
calculation.
Expand Down
21 changes: 2 additions & 19 deletions isisd/isis_lfa.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,6 @@ bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
return false;
}

/* Find SRGB associated to a System ID. */
static struct isis_sr_block *tilfa_find_srgb(struct lspdb_head *lspdb,
const uint8_t *sysid)
{
struct isis_lsp *lsp;

lsp = isis_root_system_lsp(lspdb, sysid);
if (!lsp)
return NULL;

if (!lsp->tlvs->router_cap
|| lsp->tlvs->router_cap->srgb.range_size == 0)
return NULL;

return &lsp->tlvs->router_cap->srgb;
}

struct tilfa_find_pnode_prefix_sid_args {
uint32_t sid_index;
};
Expand Down Expand Up @@ -313,7 +296,7 @@ tilfa_compute_label_stack(struct lspdb_head *lspdb,

switch (sid->type) {
case TILFA_SID_PREFIX:
srgb = tilfa_find_srgb(lspdb, sadj->id);
srgb = isis_sr_find_srgb(lspdb, sadj->id);
if (!srgb) {
zlog_warn("%s: SRGB not found for node %s",
__func__,
Expand Down Expand Up @@ -704,7 +687,7 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
struct route_table *route_table;

route_table = spftree_pc->lfa.old.spftree->route_table_backup;
if (route_node_lookup(route_table, &vertex->N.ip.dest)) {
if (route_node_lookup(route_table, &vertex->N.ip.p.dest)) {
if (IS_DEBUG_TILFA)
zlog_debug(
"ISIS-TI-LFA: %s %s already covered by node protection",
Expand Down
106 changes: 81 additions & 25 deletions isisd/isis_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -192,14 +195,15 @@ 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;

/*
* Create dummy nexthops when running SPF on a testing
* 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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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)
Expand All @@ -275,21 +296,33 @@ 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)",
old->nexthops->count, new->nexthops->count);
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 */
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
18 changes: 9 additions & 9 deletions isisd/isis_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct isis_nexthop {
int family;
union g_addr ip;
uint8_t sysid[ISIS_SYS_ID_LEN];
struct sr_nexthop_info sr;
struct isis_sr_psid_info sr;
struct mpls_label_stack *label_stack;
};

Expand All @@ -43,6 +43,8 @@ struct isis_route_info {
uint8_t flag;
uint32_t cost;
uint32_t depth;
struct isis_sr_psid_info sr;
struct isis_sr_psid_info sr_previous;
struct list *nexthops;
struct isis_route_info *backup;
};
Expand All @@ -54,15 +56,13 @@ DECLARE_HOOK(isis_route_update_hook,

void isis_nexthop_delete(struct isis_nexthop *nexthop);
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_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);

/* Walk the given table and install new routes to zebra and remove old ones.
* route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
Expand Down
Loading

0 comments on commit d47d608

Please sign in to comment.