Skip to content

Commit ecb2675

Browse files
committed
isisd: Add support for SRv6 Adjacency SIDs
An SRv6 adjacency SID is a SID that is associated with a particular adjacency. Adjacency SIDs are advertised using the SRv6 End.X SID Sub-TLV (RFC 9352 section sonic-net#8.1) or SRv6 LAN End.X SID Sub-TLV (RFC 9352 section sonic-net#8.2). This commit defines the following Adj SIDs management functions: * srv6_endx_sid_add_single: add a new SRv6 Adjacency SID * srv6_endx_sid_del: delete an SRv6 Adjacency SID * isis_srv6_endx_sid_find: lookup SRv6 End.X SID by type It also attaches some callbacks to the hooks isis_adj_state_change_hook, isis_adj_ip_enabled_hook, isis_adj_ip_disabled_hook, which are responsible for installing/removing an SRv6 Adjacency SID automatically when the state of an IS-IS adjacency changes. Signed-off-by: Carmine Scarpitta <[email protected]>
1 parent 7db1a90 commit ecb2675

File tree

6 files changed

+375
-0
lines changed

6 files changed

+375
-0
lines changed

isisd/isis_adjacency.h

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct isis_adjacency {
9898
struct list *adj_sids; /* Segment Routing Adj-SIDs. */
9999
uint32_t snmp_idx;
100100
struct listnode *snmp_list_node;
101+
102+
struct list *srv6_endx_sids; /* SRv6 End.X SIDs. */
101103
};
102104

103105
struct isis_threeway_adj;

isisd/isis_srv6.c

+308
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111

1212
#include "srv6.h"
1313
#include "termtable.h"
14+
#include "lib/lib_errors.h"
1415

1516
#include "isisd/isisd.h"
17+
#include "isisd/isis_adjacency.h"
1618
#include "isisd/isis_misc.h"
19+
#include "isisd/isis_route.h"
1720
#include "isisd/isis_srv6.h"
1821
#include "isisd/isis_zebra.h"
1922

2023
/* Local variables and functions */
2124
DEFINE_MTYPE_STATIC(ISISD, ISIS_SRV6_SID, "ISIS SRv6 Segment ID");
25+
DEFINE_MTYPE_STATIC(ISISD, ISIS_SRV6_INFO, "ISIS SRv6 information");
2226

2327
/**
2428
* Fill in SRv6 SID Structure Sub-Sub-TLV with information from an SRv6 SID.
@@ -97,6 +101,7 @@ bool isis_srv6_locator_unset(struct isis_area *area)
97101
struct listnode *node, *nnode;
98102
struct srv6_locator_chunk *chunk;
99103
struct isis_srv6_sid *sid;
104+
struct srv6_adjacency *sra;
100105

101106
if (strncmp(area->srv6db.config.srv6_locator_name, "",
102107
sizeof(area->srv6db.config.srv6_locator_name)) == 0) {
@@ -119,6 +124,10 @@ bool isis_srv6_locator_unset(struct isis_area *area)
119124
isis_srv6_sid_free(sid);
120125
}
121126

127+
/* Uninstall all local Adjacency-SIDs. */
128+
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra))
129+
srv6_endx_sid_del(sra);
130+
122131
/* Inform Zebra that we are releasing the SRv6 locator */
123132
ret = isis_zebra_srv6_manager_release_locator_chunk(
124133
area->srv6db.config.srv6_locator_name);
@@ -298,6 +307,296 @@ void isis_srv6_sid_free(struct isis_srv6_sid *sid)
298307
XFREE(MTYPE_ISIS_SRV6_SID, sid);
299308
}
300309

310+
/**
311+
* Delete all backup SRv6 End.X SIDs.
312+
*
313+
* @param area IS-IS area
314+
* @param level IS-IS level
315+
*/
316+
void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level)
317+
{
318+
struct srv6_adjacency *sra;
319+
struct listnode *node, *nnode;
320+
321+
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra))
322+
if (sra->type == ISIS_SRV6_LAN_BACKUP &&
323+
(sra->adj->level & level))
324+
srv6_endx_sid_del(sra);
325+
}
326+
327+
/* --- SRv6 End.X SID management functions ------------------- */
328+
329+
/**
330+
* Add new local End.X SID.
331+
*
332+
* @param adj IS-IS Adjacency
333+
* @param backup True to initialize backup Adjacency SID
334+
* @param nexthops List of backup nexthops (for backup End.X SIDs only)
335+
*/
336+
void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
337+
struct list *nexthops)
338+
{
339+
struct isis_circuit *circuit = adj->circuit;
340+
struct isis_area *area = circuit->area;
341+
struct srv6_adjacency *sra;
342+
struct isis_srv6_endx_sid_subtlv *adj_sid;
343+
struct isis_srv6_lan_endx_sid_subtlv *ladj_sid;
344+
struct in6_addr nexthop;
345+
uint8_t flags = 0;
346+
struct srv6_locator_chunk *chunk;
347+
uint32_t behavior;
348+
349+
if (!area || !area->srv6db.srv6_locator_chunks ||
350+
list_isempty(area->srv6db.srv6_locator_chunks))
351+
return;
352+
353+
sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag,
354+
backup ? "Backup" : "Primary");
355+
356+
/* Determine nexthop IP address */
357+
if (!circuit->ipv6_router || !adj->ll_ipv6_count)
358+
return;
359+
360+
chunk = (struct srv6_locator_chunk *)listgetdata(
361+
listhead(area->srv6db.srv6_locator_chunks));
362+
if (!chunk)
363+
return;
364+
365+
nexthop = adj->ll_ipv6_addrs[0];
366+
367+
/* Prepare SRv6 End.X as per RFC9352 section #8.1 */
368+
if (backup)
369+
SET_FLAG(flags, EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG);
370+
371+
if (circuit->ext == NULL)
372+
circuit->ext = isis_alloc_ext_subtlvs();
373+
374+
behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID))
375+
? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID
376+
: SRV6_ENDPOINT_BEHAVIOR_END_X;
377+
378+
sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra));
379+
sra->type = backup ? ISIS_SRV6_LAN_BACKUP : ISIS_SRV6_ADJ_NORMAL;
380+
sra->behavior = behavior;
381+
sra->locator = chunk;
382+
sra->structure.loc_block_len = chunk->block_bits_length;
383+
sra->structure.loc_node_len = chunk->node_bits_length;
384+
sra->structure.func_len = chunk->function_bits_length;
385+
sra->structure.arg_len = chunk->argument_bits_length;
386+
sra->nexthop = nexthop;
387+
388+
sra->sid = srv6_locator_request_sid(area, chunk, -1);
389+
if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) {
390+
XFREE(MTYPE_ISIS_SRV6_INFO, sra);
391+
return;
392+
}
393+
394+
switch (circuit->circ_type) {
395+
/* SRv6 LAN End.X SID for Broadcast interface section #8.2 */
396+
case CIRCUIT_T_BROADCAST:
397+
ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid));
398+
memcpy(ladj_sid->neighbor_id, adj->sysid,
399+
sizeof(ladj_sid->neighbor_id));
400+
ladj_sid->flags = flags;
401+
ladj_sid->algorithm = SR_ALGORITHM_SPF;
402+
ladj_sid->weight = 0;
403+
ladj_sid->behavior = sra->behavior;
404+
ladj_sid->sid = sra->sid;
405+
ladj_sid->subsubtlvs = isis_alloc_subsubtlvs(
406+
ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID);
407+
ladj_sid->subsubtlvs->srv6_sid_structure = XCALLOC(
408+
MTYPE_ISIS_SUBSUBTLV,
409+
sizeof(*ladj_sid->subsubtlvs->srv6_sid_structure));
410+
ladj_sid->subsubtlvs->srv6_sid_structure->loc_block_len =
411+
sra->structure.loc_block_len;
412+
ladj_sid->subsubtlvs->srv6_sid_structure->loc_node_len =
413+
sra->structure.loc_node_len;
414+
ladj_sid->subsubtlvs->srv6_sid_structure->func_len =
415+
sra->structure.func_len;
416+
ladj_sid->subsubtlvs->srv6_sid_structure->arg_len =
417+
sra->structure.arg_len;
418+
isis_tlvs_add_srv6_lan_endx_sid(circuit->ext, ladj_sid);
419+
sra->u.lendx_sid = ladj_sid;
420+
break;
421+
/* SRv6 End.X SID for Point to Point interface section #8.1 */
422+
case CIRCUIT_T_P2P:
423+
adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid));
424+
adj_sid->flags = flags;
425+
adj_sid->algorithm = SR_ALGORITHM_SPF;
426+
adj_sid->weight = 0;
427+
adj_sid->behavior = sra->behavior;
428+
adj_sid->sid = sra->sid;
429+
adj_sid->subsubtlvs = isis_alloc_subsubtlvs(
430+
ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID);
431+
adj_sid->subsubtlvs->srv6_sid_structure = XCALLOC(
432+
MTYPE_ISIS_SUBSUBTLV,
433+
sizeof(*adj_sid->subsubtlvs->srv6_sid_structure));
434+
adj_sid->subsubtlvs->srv6_sid_structure->loc_block_len =
435+
sra->structure.loc_block_len;
436+
adj_sid->subsubtlvs->srv6_sid_structure->loc_node_len =
437+
sra->structure.loc_node_len;
438+
adj_sid->subsubtlvs->srv6_sid_structure->func_len =
439+
sra->structure.func_len;
440+
adj_sid->subsubtlvs->srv6_sid_structure->arg_len =
441+
sra->structure.arg_len;
442+
isis_tlvs_add_srv6_endx_sid(circuit->ext, adj_sid);
443+
sra->u.endx_sid = adj_sid;
444+
break;
445+
default:
446+
flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
447+
__func__, circuit->circ_type);
448+
exit(1);
449+
}
450+
451+
/* Add Adjacency-SID in SRDB */
452+
sra->adj = adj;
453+
listnode_add(area->srv6db.srv6_endx_sids, sra);
454+
listnode_add(adj->srv6_endx_sids, sra);
455+
456+
isis_zebra_srv6_adj_sid_install(sra);
457+
}
458+
459+
/**
460+
* Add Primary and Backup local SRv6 End.X SID.
461+
*
462+
* @param adj IS-IS Adjacency
463+
*/
464+
void srv6_endx_sid_add(struct isis_adjacency *adj)
465+
{
466+
srv6_endx_sid_add_single(adj, false, NULL);
467+
}
468+
469+
/**
470+
* Delete local SRv6 End.X SID.
471+
*
472+
* @param sra SRv6 Adjacency
473+
*/
474+
void srv6_endx_sid_del(struct srv6_adjacency *sra)
475+
{
476+
struct isis_circuit *circuit = sra->adj->circuit;
477+
struct isis_area *area = circuit->area;
478+
479+
sr_debug("ISIS-SRv6 (%s): Delete SRv6 End.X SID", area->area_tag);
480+
481+
isis_zebra_srv6_adj_sid_uninstall(sra);
482+
483+
/* Release dynamic SRv6 SID and remove subTLVs */
484+
switch (circuit->circ_type) {
485+
case CIRCUIT_T_BROADCAST:
486+
isis_tlvs_del_srv6_lan_endx_sid(circuit->ext, sra->u.lendx_sid);
487+
break;
488+
case CIRCUIT_T_P2P:
489+
isis_tlvs_del_srv6_endx_sid(circuit->ext, sra->u.endx_sid);
490+
break;
491+
default:
492+
flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
493+
__func__, circuit->circ_type);
494+
exit(1);
495+
}
496+
497+
if (sra->type == ISIS_SRV6_LAN_BACKUP && sra->backup_nexthops) {
498+
sra->backup_nexthops->del =
499+
(void (*)(void *))isis_nexthop_delete;
500+
list_delete(&sra->backup_nexthops);
501+
}
502+
503+
/* Remove Adjacency-SID from the SRDB */
504+
listnode_delete(area->srv6db.srv6_endx_sids, sra);
505+
listnode_delete(sra->adj->srv6_endx_sids, sra);
506+
XFREE(MTYPE_ISIS_SRV6_INFO, sra);
507+
}
508+
509+
/**
510+
* Lookup SRv6 End.X SID by type.
511+
*
512+
* @param adj IS-IS Adjacency
513+
* @param type SRv6 End.X SID type
514+
*/
515+
struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj,
516+
enum srv6_adj_type type)
517+
{
518+
struct srv6_adjacency *sra;
519+
struct listnode *node;
520+
521+
for (ALL_LIST_ELEMENTS_RO(adj->srv6_endx_sids, node, sra))
522+
if (sra->type == type)
523+
return sra;
524+
525+
return NULL;
526+
}
527+
528+
/**
529+
* Remove all SRv6 End.X SIDs associated to an adjacency that is going down.
530+
*
531+
* @param adj IS-IS Adjacency
532+
*
533+
* @return 0
534+
*/
535+
static int srv6_adj_state_change(struct isis_adjacency *adj)
536+
{
537+
struct srv6_adjacency *sra;
538+
struct listnode *node, *nnode;
539+
540+
if (!adj->circuit->area->srv6db.config.enabled)
541+
return 0;
542+
543+
if (adj->adj_state == ISIS_ADJ_UP)
544+
return 0;
545+
546+
for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, node, nnode, sra))
547+
srv6_endx_sid_del(sra);
548+
549+
return 0;
550+
}
551+
552+
/**
553+
* When IS-IS Adjacency got one or more IPv6 addresses, add new
554+
* IPv6 address to corresponding SRv6 End.X SID accordingly.
555+
*
556+
* @param adj IS-IS Adjacency
557+
* @param family Inet Family (IPv4 or IPv6)
558+
* @param global Indicate if it concerns the Local or Global IPv6 addresses
559+
*
560+
* @return 0
561+
*/
562+
static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family,
563+
bool global)
564+
{
565+
if (!adj->circuit->area->srv6db.config.enabled || global ||
566+
family != AF_INET6)
567+
return 0;
568+
569+
srv6_endx_sid_add(adj);
570+
571+
return 0;
572+
}
573+
574+
/**
575+
* When IS-IS Adjacency doesn't have any IPv6 addresses anymore,
576+
* delete the corresponding SRv6 End.X SID(s) accordingly.
577+
*
578+
* @param adj IS-IS Adjacency
579+
* @param family Inet Family (IPv4 or IPv6)
580+
* @param global Indicate if it concerns the Local or Global IPv6 addresses
581+
*
582+
* @return 0
583+
*/
584+
static int srv6_adj_ip_disabled(struct isis_adjacency *adj, int family,
585+
bool global)
586+
{
587+
struct srv6_adjacency *sra;
588+
struct listnode *node, *nnode;
589+
590+
if (!adj->circuit->area->srv6db.config.enabled || global ||
591+
family != AF_INET6)
592+
return 0;
593+
594+
for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, node, nnode, sra))
595+
srv6_endx_sid_del(sra);
596+
597+
return 0;
598+
}
599+
301600
/**
302601
* Show Segment Routing over IPv6 (SRv6) Node.
303602
*
@@ -444,11 +743,20 @@ void isis_srv6_area_term(struct isis_area *area)
444743
void isis_srv6_init(void)
445744
{
446745
install_element(VIEW_NODE, &show_srv6_node_cmd);
746+
747+
/* Register hooks. */
748+
hook_register(isis_adj_state_change_hook, srv6_adj_state_change);
749+
hook_register(isis_adj_ip_enabled_hook, srv6_adj_ip_enabled);
750+
hook_register(isis_adj_ip_disabled_hook, srv6_adj_ip_disabled);
447751
}
448752

449753
/**
450754
* IS-IS SRv6 global terminate.
451755
*/
452756
void isis_srv6_term(void)
453757
{
758+
/* Unregister hooks. */
759+
hook_unregister(isis_adj_state_change_hook, srv6_adj_state_change);
760+
hook_unregister(isis_adj_ip_enabled_hook, srv6_adj_ip_enabled);
761+
hook_unregister(isis_adj_ip_disabled_hook, srv6_adj_ip_disabled);
454762
}

isisd/isis_srv6.h

+11
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ struct isis_srv6_db {
120120
/* List of SRv6 SIDs allocated by the IS-IS instance */
121121
struct list *srv6_sids;
122122

123+
/* List of SRv6 End.X SIDs allocated by the IS-IS instance */
124+
struct list *srv6_endx_sids;
125+
123126
/* Area SRv6 configuration. */
124127
struct {
125128
/* Administrative status of SRv6 */
@@ -164,4 +167,12 @@ void isis_srv6_end_sid2subtlv(const struct isis_srv6_sid *sid,
164167
void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc,
165168
struct isis_srv6_locator_tlv *loc_tlv);
166169

170+
void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
171+
struct list *nexthops);
172+
void srv6_endx_sid_add(struct isis_adjacency *adj);
173+
void srv6_endx_sid_del(struct srv6_adjacency *sra);
174+
struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj,
175+
enum srv6_adj_type type);
176+
void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level);
177+
167178
#endif /* _FRR_ISIS_SRV6_H */

0 commit comments

Comments
 (0)