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) {
return ISIS_WARNING;
}
+ isis_area_delete_backup_adj_sids(area, level);
isis_area_invalidate_routes(area, level);
if (IS_DEBUG_SPF_EVENTS)
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 ----------------------------------------- */
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.
*
/**
* 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;
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:
*/
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,
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",
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.
*
/* 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;
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);
*/
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;
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;
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);
}