mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 16:20:08 +00:00
isisd: implement TI-LFA protection for Adj-SIDs
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
c951ee6eee
commit
054fda12f0
@ -678,8 +678,24 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the adjacency was already covered by node protection.
|
||||
* Check if the route/adjacency was already covered by node protection.
|
||||
*/
|
||||
if (VTYPE_IS(vertex->type)) {
|
||||
struct isis_adjacency *adj;
|
||||
|
||||
adj = isis_adj_find(spftree_pc->area, spftree_pc->level,
|
||||
vertex->N.id);
|
||||
if (adj
|
||||
&& isis_sr_adj_sid_find(adj, spftree_pc->family,
|
||||
ISIS_SR_LAN_BACKUP)) {
|
||||
if (IS_DEBUG_TILFA)
|
||||
zlog_debug(
|
||||
"ISIS-TI-LFA: %s %s already covered by node protection",
|
||||
vtype2string(vertex->type), buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (VTYPE_IP(vertex->type)) {
|
||||
struct route_table *route_table;
|
||||
|
||||
|
@ -1236,6 +1236,29 @@ static void add_to_paths(struct isis_spftree *spftree,
|
||||
vertex->d_N);
|
||||
#endif /* EXTREME_DEBUG */
|
||||
|
||||
if (VTYPE_IS(vertex->type)
|
||||
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
|
||||
if (listcount(vertex->Adj_N) > 0) {
|
||||
if (spftree->type == SPF_TYPE_TI_LFA) {
|
||||
struct isis_adjacency *adj;
|
||||
|
||||
if (isis_lfa_check(spftree, vertex) != 0)
|
||||
return;
|
||||
|
||||
adj = isis_adj_find(area, spftree->level,
|
||||
vertex->N.id);
|
||||
if (adj)
|
||||
sr_adj_sid_add_single(
|
||||
adj, spftree->family, true,
|
||||
vertex->Adj_N);
|
||||
}
|
||||
} else if (IS_DEBUG_SPF_EVENTS)
|
||||
zlog_debug(
|
||||
"ISIS-Spf: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d",
|
||||
vid2string(vertex, buff, sizeof(buff)),
|
||||
vertex->depth, vertex->d_N);
|
||||
}
|
||||
|
||||
if (VTYPE_IP(vertex->type)
|
||||
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
|
||||
if (listcount(vertex->Adj_N) > 0) {
|
||||
@ -1466,6 +1489,7 @@ static int isis_run_spf_cb(struct thread *thread)
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
isis_area_delete_backup_adj_sids(area, level);
|
||||
isis_area_invalidate_routes(area, level);
|
||||
|
||||
if (IS_DEBUG_SPF_EVENTS)
|
||||
|
@ -56,6 +56,7 @@ static void sr_local_block_delete(struct isis_area *area);
|
||||
static int sr_local_block_init(struct isis_area *area);
|
||||
static void sr_adj_sid_update(struct sr_adjacency *sra,
|
||||
struct sr_local_block *srlb);
|
||||
static void sr_adj_sid_del(struct sr_adjacency *sra);
|
||||
|
||||
/* --- RB-Tree Management functions ----------------------------------------- */
|
||||
|
||||
@ -1254,6 +1255,23 @@ static void process_node_changes(struct isis_area *area, int level,
|
||||
process_prefix_changes(srn, srp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all backup Adj-SIDs.
|
||||
*
|
||||
* @param area IS-IS area
|
||||
* @param level IS-IS level
|
||||
*/
|
||||
void isis_area_delete_backup_adj_sids(struct isis_area *area, int level)
|
||||
{
|
||||
struct sr_adjacency *sra;
|
||||
struct listnode *node, *nnode;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
|
||||
if (sra->type == ISIS_SR_LAN_BACKUP
|
||||
&& (sra->adj->level & level))
|
||||
sr_adj_sid_del(sra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
|
||||
*
|
||||
@ -1499,12 +1517,13 @@ static int sr_local_block_release_label(struct sr_local_block *srlb,
|
||||
/**
|
||||
* Add new local Adjacency-SID.
|
||||
*
|
||||
* @param adj IS-IS Adjacency
|
||||
* @param family Inet Family (IPv4 or IPv6)
|
||||
* @param backup True to initialize backup Adjacency SID
|
||||
* @param adj IS-IS Adjacency
|
||||
* @param family Inet Family (IPv4 or IPv6)
|
||||
* @param backup True to initialize backup Adjacency SID
|
||||
* @param nexthops List of backup nexthops (for backup Adj-SIDs only)
|
||||
*/
|
||||
static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
|
||||
bool backup)
|
||||
void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
|
||||
struct list *nexthops)
|
||||
{
|
||||
struct isis_circuit *circuit = adj->circuit;
|
||||
struct isis_area *area = circuit->area;
|
||||
@ -1555,9 +1574,25 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
|
||||
|
||||
sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
|
||||
sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
|
||||
sra->input_label = input_label;
|
||||
sra->nexthop.family = family;
|
||||
sra->nexthop.address = nexthop;
|
||||
sra->nexthop.label = input_label;
|
||||
|
||||
if (backup && nexthops) {
|
||||
struct isis_vertex_adj *vadj;
|
||||
struct listnode *node;
|
||||
|
||||
sra->backup_nexthops = list_new();
|
||||
for (ALL_LIST_ELEMENTS_RO(nexthops, node, vadj)) {
|
||||
struct isis_adjacency *adj = vadj->sadj->adj;
|
||||
struct mpls_label_stack *label_stack;
|
||||
|
||||
label_stack = vadj->label_stack;
|
||||
adjinfo2nexthop(family, sra->backup_nexthops, adj,
|
||||
label_stack);
|
||||
}
|
||||
}
|
||||
|
||||
switch (circuit->circ_type) {
|
||||
/* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
|
||||
case CIRCUIT_T_BROADCAST:
|
||||
@ -1603,8 +1638,7 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
|
||||
*/
|
||||
static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
|
||||
{
|
||||
sr_adj_sid_add_single(adj, family, false);
|
||||
sr_adj_sid_add_single(adj, family, true);
|
||||
sr_adj_sid_add_single(adj, family, false, NULL);
|
||||
}
|
||||
|
||||
static void sr_adj_sid_update(struct sr_adjacency *sra,
|
||||
@ -1616,16 +1650,16 @@ static void sr_adj_sid_update(struct sr_adjacency *sra,
|
||||
isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
|
||||
|
||||
/* Got new label in the new SRLB */
|
||||
sra->nexthop.label = sr_local_block_request_label(srlb);
|
||||
if (sra->nexthop.label == MPLS_INVALID_LABEL)
|
||||
sra->input_label = sr_local_block_request_label(srlb);
|
||||
if (sra->input_label == MPLS_INVALID_LABEL)
|
||||
return;
|
||||
|
||||
switch (circuit->circ_type) {
|
||||
case CIRCUIT_T_BROADCAST:
|
||||
sra->u.ladj_sid->sid = sra->nexthop.label;
|
||||
sra->u.ladj_sid->sid = sra->input_label;
|
||||
break;
|
||||
case CIRCUIT_T_P2P:
|
||||
sra->u.adj_sid->sid = sra->nexthop.label;
|
||||
sra->u.adj_sid->sid = sra->input_label;
|
||||
break;
|
||||
default:
|
||||
flog_warn(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
|
||||
@ -1669,12 +1703,38 @@ static void sr_adj_sid_del(struct sr_adjacency *sra)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sra->type == ISIS_SR_LAN_BACKUP && sra->backup_nexthops) {
|
||||
sra->backup_nexthops->del =
|
||||
(void (*)(void *))isis_nexthop_delete;
|
||||
list_delete(&sra->backup_nexthops);
|
||||
}
|
||||
|
||||
/* Remove Adjacency-SID from the SRDB */
|
||||
listnode_delete(area->srdb.adj_sids, sra);
|
||||
listnode_delete(sra->adj->adj_sids, sra);
|
||||
XFREE(MTYPE_ISIS_SR_INFO, sra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup Segment Routing Adj-SID by family and type.
|
||||
*
|
||||
* @param adj IS-IS Adjacency
|
||||
* @param family Inet Family (IPv4 or IPv6)
|
||||
* @param type Adjacency SID type
|
||||
*/
|
||||
struct sr_adjacency *isis_sr_adj_sid_find(struct isis_adjacency *adj,
|
||||
int family, enum sr_adj_type type)
|
||||
{
|
||||
struct sr_adjacency *sra;
|
||||
struct listnode *node;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, node, sra))
|
||||
if (sra->nexthop.family == family && sra->type == type)
|
||||
return sra;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all Adjacency-SIDs associated to an adjacency that is going down.
|
||||
*
|
||||
|
@ -84,13 +84,18 @@ struct sr_adjacency {
|
||||
/* Adjacency type. */
|
||||
enum sr_adj_type type;
|
||||
|
||||
/* Adjacency-SID input label. */
|
||||
mpls_label_t input_label;
|
||||
|
||||
/* Adjacency-SID nexthop information. */
|
||||
struct {
|
||||
int family;
|
||||
union g_addr address;
|
||||
mpls_label_t label;
|
||||
} nexthop;
|
||||
|
||||
/* Adjacency-SID TI-LFA backup nexthops. */
|
||||
struct list *backup_nexthops;
|
||||
|
||||
/* (LAN-)Adjacency-SID Sub-TLV. */
|
||||
union {
|
||||
struct isis_adj_sid *adj_sid;
|
||||
@ -277,6 +282,12 @@ extern void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg,
|
||||
extern void isis_sr_nexthop_update(struct sr_nexthop_info *srnh,
|
||||
mpls_label_t label);
|
||||
extern void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh);
|
||||
extern void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
|
||||
bool backup, struct list *nexthops);
|
||||
extern struct sr_adjacency *isis_sr_adj_sid_find(struct isis_adjacency *adj,
|
||||
int family,
|
||||
enum sr_adj_type type);
|
||||
extern void isis_area_delete_backup_adj_sids(struct isis_area *area, int level);
|
||||
extern void isis_area_verify_sr(struct isis_area *area);
|
||||
extern int isis_sr_start(struct isis_area *area);
|
||||
extern void isis_sr_stop(struct isis_area *area);
|
||||
|
@ -471,6 +471,7 @@ void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
|
||||
*/
|
||||
void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
|
||||
{
|
||||
struct isis *isis = sra->adj->circuit->area->isis;
|
||||
struct zapi_labels zl;
|
||||
struct zapi_nexthop *znh;
|
||||
|
||||
@ -482,11 +483,11 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
|
||||
|
||||
sr_debug(" |- %s label %u for interface %s",
|
||||
cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
|
||||
sra->nexthop.label, sra->adj->circuit->interface->name);
|
||||
sra->input_label, sra->adj->circuit->interface->name);
|
||||
|
||||
memset(&zl, 0, sizeof(zl));
|
||||
zl.type = ZEBRA_LSP_ISIS_SR;
|
||||
zl.local_label = sra->nexthop.label;
|
||||
zl.local_label = sra->input_label;
|
||||
zl.nexthop_num = 1;
|
||||
znh = &zl.nexthops[0];
|
||||
znh->gate = sra->nexthop.address;
|
||||
@ -497,6 +498,24 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
|
||||
znh->label_num = 1;
|
||||
znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
|
||||
|
||||
/* Set backup nexthops. */
|
||||
if (sra->type == ISIS_SR_LAN_BACKUP) {
|
||||
int count;
|
||||
|
||||
count = isis_zebra_add_nexthops(isis, sra->backup_nexthops,
|
||||
zl.backup_nexthops,
|
||||
ISIS_MPLS_NEXTHOP_BACKUP, 0);
|
||||
if (count > 0) {
|
||||
SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
|
||||
zl.backup_nexthop_num = count;
|
||||
|
||||
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
|
||||
znh->backup_num = count;
|
||||
for (int i = 0; i < count; i++)
|
||||
znh->backup_idx[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
(void)zebra_send_mpls_labels(zclient, cmd, &zl);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user