11
11
12
12
#include "srv6.h"
13
13
#include "termtable.h"
14
+ #include "lib/lib_errors.h"
14
15
15
16
#include "isisd/isisd.h"
17
+ #include "isisd/isis_adjacency.h"
16
18
#include "isisd/isis_misc.h"
19
+ #include "isisd/isis_route.h"
17
20
#include "isisd/isis_srv6.h"
18
21
#include "isisd/isis_zebra.h"
19
22
20
23
/* Local variables and functions */
21
24
DEFINE_MTYPE_STATIC (ISISD , ISIS_SRV6_SID , "ISIS SRv6 Segment ID" );
25
+ DEFINE_MTYPE_STATIC (ISISD , ISIS_SRV6_INFO , "ISIS SRv6 information" );
22
26
23
27
/**
24
28
* 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)
97
101
struct listnode * node , * nnode ;
98
102
struct srv6_locator_chunk * chunk ;
99
103
struct isis_srv6_sid * sid ;
104
+ struct srv6_adjacency * sra ;
100
105
101
106
if (strncmp (area -> srv6db .config .srv6_locator_name , "" ,
102
107
sizeof (area -> srv6db .config .srv6_locator_name )) == 0 ) {
@@ -119,6 +124,10 @@ bool isis_srv6_locator_unset(struct isis_area *area)
119
124
isis_srv6_sid_free (sid );
120
125
}
121
126
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
+
122
131
/* Inform Zebra that we are releasing the SRv6 locator */
123
132
ret = isis_zebra_srv6_manager_release_locator_chunk (
124
133
area -> srv6db .config .srv6_locator_name );
@@ -298,6 +307,296 @@ void isis_srv6_sid_free(struct isis_srv6_sid *sid)
298
307
XFREE (MTYPE_ISIS_SRV6_SID , sid );
299
308
}
300
309
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
+
301
600
/**
302
601
* Show Segment Routing over IPv6 (SRv6) Node.
303
602
*
@@ -444,11 +743,20 @@ void isis_srv6_area_term(struct isis_area *area)
444
743
void isis_srv6_init (void )
445
744
{
446
745
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 );
447
751
}
448
752
449
753
/**
450
754
* IS-IS SRv6 global terminate.
451
755
*/
452
756
void isis_srv6_term (void )
453
757
{
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 );
454
762
}
0 commit comments