Skip to content

SRv6 uSID (micro-SID) support for traffic flow packet headers (RFC 9800)#478

Merged
SuryyaKrJana merged 57 commits into
masterfrom
srv6-raw-traffic
Jun 10, 2026
Merged

SRv6 uSID (micro-SID) support for traffic flow packet headers (RFC 9800)#478
SuryyaKrJana merged 57 commits into
masterfrom
srv6-raw-traffic

Conversation

@SuryyaKrJana

@SuryyaKrJana SuryyaKrJana commented May 14, 2026

Copy link
Copy Markdown
Contributor

Feature Overview

  • Related Issue: (e.g., Fixes #<issue_number>)

  • Brief Description:
    SRv6 uSID (micro-SID) support for traffic flow packet headers (RFC 9800)

  • Two new encoding paths are added to allow traffic generation with SRv6 uSID compressed segment identifiers:

  • No-SRH reduced encapsulation (ipv6.yaml): new dst_usids field on the IPv6 header (Flow.Ipv6.UsidDst) — packs a locator block + ordered uSID list directly into the 128-bit IPv6 dst with no Segment Routing Header. For paths that fit in a single uSID container (e.g. F3216: locator /32 + up to 6 × 16-bit uSIDs).

  • SRH-based uSID encapsulation (ipv6_routing.yaml): new segment_routing_usid choice on Flow.Ipv6Routing (Flow.Ipv6SegmentRoutingUsid) — carries multiple compressed uSID containers in an SRH segment list for multi-hop paths that exceed one container.

  • Supporting additions: shared Flow.Ipv6SRH.PadTlv schema (optional SRH padding TLV for 8-byte alignment), OAM flag support (Flow.Ipv6SegmentRouting.uSidFlags), and description/path-depth fixes across the existing SR-MPLS IS-IS device schemas.


Feature Details

  • Redocly docs for this feature/branch

  • New Locations/Nomenclature:
    Specify where new attributes/nodes have been added in the models hierarchy to allow viewers to quickly navigate to the correct areas in the generated Redocly view corresponding to the model change.

  • Dev-Snappi branch reference

  • Example command to fetch the srv6-raw-traffic

    go get github.com/open-traffic-generator/snappi/gosnappi@<srv6-raw-traffic>
    

Code snippets

Code snippets

Example - 1: Multiple uSIDs with NO SRH: 3-hop path packed into one F3216 uSID container,
placed directly in the IPv6 destination via ipv6.dst_usids - no routing extension
header required.

OTG model used:
Flow.Ipv6 (dst = uSID container, NH auto-set to 17 by next header)
F3216 uSID container layout (128 bits):
fc00:0:1:2:3::
Locator-Block = fc00:0000 (32 bits, shared domain prefix)
uSID-1 = 0001 (16 bits, hop 1 - egress of node 1)
uSID-2 = 0002 (16 bits, hop 2 - egress of node 2)
uSID-3 = 0003 (16 bits, hop 3 - egress of node 3)
Remaining = 0:: (48 bits, zeros = end of uSID list)

 #  USID creation without helper API
    .......................
     .........................
    f.tx_rx.port.tx_name = p1.name
    f.tx_rx.port.rx_name = p2.name
   
    eth = f.packet.add().ethernet
    eth.src.value = "00:11:22:33:44:55"
    eth.dst.value = "00:aa:bb:cc:dd:ee"

    ip6 = f.packet.add().ipv6
    ip6.src.value = "2001:db8::1"
    du = ip6.dst_usids
    du.locator.value = "fc00::"
    du.locator_length.value = 32
    du.usids = ["0001", "0002", "0003"]
   

Example - 2: Multiple uSIDs with 1 uSID SRH container: 3-hop path packed in one F3216 uSID
container, carried inside a uSID SRH extension header with a single segment entry.

OTG model used:
Flow.Ipv6 (NH=43, dst = uSID container)
Flow.Ipv6ExtHeader.routing.segment_routing_usid (Flow.Ipv6SegmentRoutingUsid)
segment_list: 1 entry (last_entry=0, segments_left=0)

F3216 uSID container layout (128 bits):
fc00:0:1:2:3::
Locator-Block = fc00:0000 (32 bits, shared domain prefix)
uSID-1 = 0001 (16 bits, hop 1)
uSID-2 = 0002 (16 bits, hop 2)
uSID-3 = 0003 (16 bits, hop 3)
Remaining = 0:: (48 bits, zeros = end of uSID list)

   usid_container = "fc00:0:1:2:3::"
    locator        = "fc00::"
    locator_length = 32
    usids          = ["0001", "0002", "0003"]
    segments_left  = 0
    last_entry     = 0

    f.tx_rx.port.tx_name = p1.name
    f.tx_rx.port.rx_name = p2.name
   
    eth = f.packet.add().ethernet
    eth.src.value = "00:11:22:33:44:55"
    eth.dst.value = "00:aa:bb:cc:dd:ee"

    ip6 = f.packet.add().ipv6
    ip6.src.value = "2001:db8::1"
    du = ip6.dst_usids
    du.locator.value        = locator
    du.locator_length.value = locator_length
    du.usids                = list(usids)
    ip6.next_header.value = 43

    usid = f.packet.add().ipv6_extension_header.routing.segment_routing_usid
    usid.segments_left.value = segments_left
    usid.last_entry.value    = last_entry
    usid.tag.value           = 0

    seg = usid.segment_list.segment()[-1]
    seg.locator.value        = locator
    seg.locator_length.value = locator_length
    seg.usids                = list(usids)

Example 3: Multiple uSIDs with more than 1 uSID SRH container: 4-hop path spread across
2 F3216 uSID containers, carried in a uSID SRH with 2 segment list entries.

OTG model used:
Flow.Ipv6 (NH=43, dst assembled from dst_usids)
Flow.Ipv6ExtHeader.routing.segment_routing_usid
segment_list: 2 entries (last_entry=1, segments_left=1)
segment[0]:
locator.value = "fc00::"
locator_length.value = 32
usids = ["0001", "0002"]
segment[1]:
locator.value = "fc00::"
locator_length.value = 32
usids = ["0003", "0004"]

   locator        = "fc00::"
    locator_length = 32
    container1     = "fc00:0:1:2::"
    usids_c1       = ["0001", "0002"]
    container2     = "fc00:0:3:4::"
    usids_c2       = ["0003", "0004"]
    segments_left  = 1
    last_entry     = 1

    f.tx_rx.port.tx_name = p1.name
    f.tx_rx.port.rx_name = p2.name


    eth = f.packet.add().ethernet
    eth.src.value = "00:11:22:33:44:55"
    eth.dst.value = "00:aa:bb:cc:dd:ee"

    ip6 = f.packet.add().ipv6
    ip6.src.value = "2001:db8::1"
    du = ip6.dst_usids
    du.locator.value        = locator
    du.locator_length.value = locator_length
    du.usids                = list(usids_c1)
    ip6.next_header.value = 43

    usid = f.packet.add().ipv6_extension_header.routing.segment_routing_usid
    usid.segments_left.value = segments_left
    usid.last_entry.value    = last_entry
    usid.tag.value           = 0

    seg0 = usid.segment_list.segment()[-1]
    seg0.locator.value        = locator
    seg0.locator_length.value = locator_length
    seg0.usids                = list(usids_c1)

    seg1 = usid.segment_list.segment()[-1]
    seg1.locator.value        = locator
    seg1.locator_length.value = locator_length
    seg1.usids                = list(usids_c2)

** Example 4: RFC 9800 Figure 5 — REPLACE-CSID Compressed SID List (7 SIDs)**

(REPLACE-CSID flavor). Parameters: LBL=48 bits, LNFL=32 bits, K=4 slots.
Container 1 — outer IPv6 DA (full SRv6 SID, not in SRH):
[Locator-Block (48b) = 2001:db8::] [1st CSID (32b) = 0x00010001] [Arg=0 (48b)]
Assembled DA: 2001:db8:0:1:1::

Container 2 — SRH seg[1] (packed, fully filled, processes CSIDs 2-5):
Packing (usids[i] -> position K-1-i, i.e. usids[0] at LSB bits 96-127):
position 3 (LSB bits 96-127): 2nd CSID = 0x00020002
position 2 (bits 64-95): 3rd CSID = 0x00030003
position 1 (bits 32-63): 4th CSID = 0x00040004
position 0 (MSB bits 0-31): 5th CSID = 0x00050005
Wire (MSB->LSB): [00050005][00040004][00030003][00020002]
IPv6: 5:5:4:4:3:3:2:2

Container 3 — SRH seg[0] (packed, partially filled, processes CSIDs 6-7):
Packing:
position 3 (LSB bits 96-127): 6th CSID = 0x00060006
position 2 (bits 64-95): 7th CSID = 0x00070007
positions 1, 0 (MSB end): zeros (end-of-CSID-list padding)
Wire (MSB->LSB): [00000000][00000000][00070007][00060006]
IPv6: ::7:7:6:6
SRH: last_entry=1 (2 entries: seg[0] and seg[1]), segments_left=1.

    # Container 1: REPLACE-CSID first SID in outer IPv6 DA via dst_usids.
    # LBL=48 (2001:0db8:0000), LNFL=32, CSID1=0x00010001, Arg=0 -> 2001:db8:0:1:1::
    active_dst        = "2001:db8:0:1:1::"
    da_locator        = "2001:db8::"
    da_locator_length = 48
    da_usids          = ["00010001"]
    segments_left = 1
    last_entry    = 1

    # Container 3 — seg[0] (last entry in SRH; CSIDs 6-7, 2 of K=4 slots used).
    # Exactly K=4 CSIDs: slots 0-1 zero, usids[2]=CSID-7, usids[3]=CSID-6 (LSB, first processed).
    # Wire: [00000000][00000000][00070007][00060006] = ::7:7:6:6
    csids_seg0    = ["00000000", "00000000", "00070007", "00060006"]

    # Container 2 — seg[1] (second entry; CSIDs 2-5, all K=4 slots used).
    # Exactly K=4 CSIDs: usids[0]=CSID-5 (MSB), usids[3]=CSID-2 (LSB, first processed).
    # Wire: [00050005][00040004][00030003][00020002] = 5:5:4:4:3:3:2:2
    csids_seg1    = ["00050005", "00040004", "00030003", "00020002"]

    f.tx_rx.port.tx_name = p1.name
    f.tx_rx.port.rx_name = p2.name
 
    eth = f.packet.add().ethernet
    eth.src.value = "00:11:22:33:44:55"
    eth.dst.value = "00:aa:bb:cc:dd:ee"

    # Outer IPv6: DA = container 1 assembled from dst_usids.
    ip6 = f.packet.add().ipv6
    ip6.src.value = "2001:db8::1"
    du = ip6.dst_usids
    du.locator.value        = da_locator
    du.locator_length.value = da_locator_length
    du.usids                = list(da_usids)
    ip6.next_header.value = 43

    # REPLACE-CSID SRH: 2 packed containers (locator_length=0 = packed format).
    usid_hdr = f.packet.add().ipv6_extension_header.routing.segment_routing_usid
    usid_hdr.segments_left.value = segments_left
    usid_hdr.last_entry.value    = last_entry
    usid_hdr.flags.oam.value     = 0
    usid_hdr.tag.value           = 0

    # seg[0] added first => index 0 in segment_list = last SRH entry (CSIDs 6-7).
    seg0 = usid_hdr.segment_list.segment()[-1]
    seg0.locator.value        = "::0"
    seg0.locator_length.value = 0
    seg0.usids                = list(csids_seg0)

    # seg[1] added second => index 1 in segment_list (CSIDs 2-5, fully packed).
    seg1 = usid_hdr.segment_list.segment()[-1]
    seg1.locator.value        = "::0"
    seg1.locator_length.value = 0
    seg1.usids                = list(csids_seg1)

SuryyaKrJana and others added 30 commits April 22, 2026 11:34
New file device/isis/srv6.yaml adds 7 schemas for SRv6 config:
  IsisSRv6.NodeCapability, NodeMsd, LinkMsd -- SRv6 Caps Sub-TLV (type 25)
  with O-flag, C-flag (uSID), and MSD types 41-45 + T.Insert (43)
  IsisSRv6.Locator -- SRv6 Locator TLV (type 27) with 20 fields including
  Flex-Algo algorithm binding, Prefix Attribute Flags (RFC 7794 X/R/N/A),
  Source Router ID sub-TLVs (RFC 9350), and locator-as-prefix controls
  IsisSRv6.EndSid -- End SID sub-TLV (type 5), 11 endpoint behaviors
  IsisSRv6.AdjSid -- End.X SID sub-TLV (type 43/44), 10 endpoint behaviors
  IsisSRv6.SidStructure -- SID Structure sub-sub-TLV (type 1)

Modified device/isis/segmentrouting.yaml:
  Isis.SegmentRouting: added srv6_locators array (uid 2)
  Isis.RouterCapability: added srv6_capability (uid 8)

Modified device/isis/interface.yaml:
  Isis.Interface: added srv6_adj_sids (uid 15) and srv6_link_msd (uid 16)

Modified result/isislsp.yaml:
  IsisLsp.Tlvs: added srv6_locator_tlvs (uid 9)
  IsisLsp.Capability: added srv6_capability (uid 7)
  IsisLsp.ExtendedNeighbor: added srv6_adj_sids (uid 3)
  New schemas: SRv6Capability, SRv6NodeMsd, SRv6LocatorTlv, SRv6EndSid,
  SRv6AdjSid, SRv6SidStructure

Added MODEL-GUIDE.md best-practice sections:
  Object presence vs enable booleans, config vs state schema patterns,
  required+default constraint, cross-file $ref, build instructions,
  artifacts/ must not be committed

Added project_isis_srv6.md design record for this feature branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RFC 9350 Source Router ID sub-TLVs (type 11/12) are Flex-Algo specific
and out of scope for this delivery phase. Removed:
- include_source_router_id / ipv4_source_router_id / ipv6_source_router_id
  (uids 18-20) from IsisSRv6.Locator
- ipv4_source_router_id / ipv6_source_router_id (uids 13-14) from
  IsisLsp.SRv6LocatorTlv

The algorithm field (uid 4) is retained — it is a mandatory SRv6
locator wire-format field per RFC 9352, not Flex-Algo specific.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace flat prefix_attr_enabled + x_flag/r_flag/n_flag/a_flag fields on
IsisSRv6.Locator (uids 13-17) with a single prefix_attributes object
(uid 13) referencing the new IsisSRv6.PrefixAttributes schema.

Object presence/absence replaces the boolean gate: when present, the
Prefix Attribute Flags Sub-TLV (RFC 7794, sub-TLV type 4) is advertised;
when absent, it is suppressed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… lifecycle API

- flow/ipv6.yaml: add ipv4:4 constant to next_header for IPinIPv6 (USD) stacks
- flow/ipv6_routing.yaml: add routing_type (UID 6, RFC 8754 Routing Type 4),
  srv6_encap_mode (UID 7, uN variant selector), usid_container (UID 2) on
  Segment (non-breaking, keeps existing segment UID 1), new USidContainer
  and USid schemas for structured F3216 uSID container assembly (RFC 9800)
- control/isis.yaml: extend Action.Protocol.Isis with srv6 choice (UID 2),
  add full Srv6.MyLocalSid add/modify/delete lifecycle hierarchy (RFC 8986 S4)
- device/isis/srv6.yaml: update EndSid description, add x-reserved-field-uids
- .gitignore: add .venv

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RFC alignment fixes in device/isis/srv6.yaml:
- Correct RFC 8986 endpoint behavior codepoints: end_dt6 (16), end_dt4 (17),
  end_dt46 (18), end_dx6 (14), end_dx4 (15)
- Fix mt_id maximum 255 to 4095 per RFC 5120 Section 2 (12-bit field)
- Remove sid_structure from IsisSRv6.AdjSid (RFC 9352 Section 9: structure
  is locator-level only); reserve uid 9
- Remove IsisSRv6.NodeMsd schema and node_msds from NodeCapability; reserve uid 2
- Remove IsisSRv6.LinkMsd schema
- Remove a_flag from IsisSRv6.PrefixAttributes (X/R/N flags only); reserve uid 4

Scope changes in device/isis/interface.yaml:
- Remove srv6_link_msd from Isis.Interface; reserve uid 16

Scope changes in control/isis.yaml:
- Remove SRv6 My Local SID control actions deferred to a future PR; reserve uid 3

All descriptions updated to RFC/implementation-agnostic language.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…DEL-GUIDE.md

x-reserved-field-uids are only needed for released schemas to prevent wire-format
corruption. All SRv6 schemas are on an unreleased feature branch, so reservations
added during the design phase are unnecessary and have been removed from:
- device/isis/srv6.yaml (NodeCapability, PrefixAttributes, EndSid, AdjSid)
- device/isis/interface.yaml (Isis.Interface)
- control/isis.yaml (Action.Protocol.Isis)

MODEL-GUIDE.md reverted to origin/master baseline; internal guidance (cross-file
$ref paths, object presence gate, UID lifecycle) moved to the private ai/CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a second choice 'segment_routing_usid' to Flow.Ipv6Routing alongside
the existing 'segment_routing'. The new choice points to a new
Flow.Ipv6SegmentRoutingUsid schema whose segment_list entries are plain
pre-computed 128-bit uSID container IPv6 addresses (RFC 9800 Section 4).

Key design decisions:
- No decomposition fields (locator_block_length, etc.) in the flow schema;
  those are control-plane concepts not present on the wire.
- Users supply the pre-computed container value directly, enabling raw
  traffic generation independent of any control plane configuration.
- Flow.Ipv6SegmentRouting is unchanged; the new choice is non-breaking.
- routing_type (always 4 per RFC 8754) is not exposed as a field.
- srv6_encap_mode removed; the choice in Flow.Ipv6Routing is the signal.
- Packet format diagrams added to both schema descriptions for Redocly.
- Max capacity documented: 127 containers per SRH, F3216 = 3 uSIDs/container.
- Remove duplicate ipv4:4 constant from Flow.Ipv6.next_header (kept ip_in_ip:4).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ed artifacts

Do not commit files under artifacts/ - they are auto-generated by CI.
Add an explicit rule to the Pull Requests section of MODEL-GUIDE.md
documenting this convention.

Also revert artifacts/openapi.yaml and artifacts/otg.proto to their
pre-commit state; these were incorrectly included in the previous commit.
Only source YAML files under flow/ and config/ should be committed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SRv6 OAM is a P1 PRD item deferred to a dedicated future PR.
Removed the oam field from Flow.Ipv6SegmentRouting.Flags and
renumbered alert from uid 3 to uid 2 (pre-release branch, no
reservation needed per UID lifecycle rules).

Flags now: protected (uid 1), alert (uid 2).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…SD fields

device/isis/srv6.yaml:
- Add new IsisSRv6.Msd object (RFC 9352 Section 6) with max_sl, max_end_pop_srh,
  max_h_encaps, max_end_d_srh, max_t_insert, max_t_encaps (UIDs 1-6)
- Add node_msds (UID 2) on IsisSRv6.NodeCapability referencing IsisSRv6.Msd
- Trim c_flag description to remove worked example (moved to docs)

device/isis/interface.yaml:
- Add srv6_link_msd (UID 16) on Isis.Interface referencing IsisSRv6.Msd

flow/packet-headers/ipv6_routing.yaml:
- Add SRH TLV fields: ingress_node_tlv (UID 6, RFC 9259 Section 3.1),
  egress_node_tlv (UID 7, RFC 9259 Section 3.2), opaque_tlv (UID 8),
  pad_tlv (UID 9) on Flow.Ipv6SegmentRouting
- Simplify Flow.Ipv6SegmentRouting description

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SuryyaKrJana and others added 12 commits May 11, 2026 19:52
…on input

New Flow.Ipv6.UsidDst schema (locator, locator_length, usids) lets callers supply
a structured locator + uSID list instead of manually packing the 128-bit IPv6 dst.
ipv6_routing.yaml descriptions updated to reference ipv6.dst_usids.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SuryyaKrJana SuryyaKrJana changed the title srv6-raw-traffic: This model is created from isis-srv6-review but discarded isis-srv6 control plane. srv6-raw-traffic: This model is created from isis-srv6-review. May 21, 2026
@apratimmukherjee apratimmukherjee changed the title srv6-raw-traffic: This model is created from isis-srv6-review. SRv6 uSID (micro-SID) support for traffic flow packet headers (RFC 9800) Jun 4, 2026

@apratimmukherjee apratimmukherjee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some cleanup is needed.
Main issue : Need to decide on array of hex vs array of object with usid (hex )

Comment thread control/isis.yaml Outdated
Comment thread flow/packet-headers/ipv6.yaml Outdated
Comment thread design_usids_dst.md Outdated
Comment thread project_isis_srv6.md Outdated
Comment thread flow/packet-headers/ipv6_routing.yaml Outdated
Comment thread flow/packet-headers/ipv6.yaml Outdated
Comment thread flow/packet-headers/ipv6.yaml Outdated
Comment thread flow/packet-headers/ipv6_routing.yaml Outdated
@SuryyaKrJana SuryyaKrJana merged commit 84e7ce9 into master Jun 10, 2026
@SuryyaKrJana SuryyaKrJana deleted the srv6-raw-traffic branch June 10, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants