Configuring SRv6

This document describes the device data model parameters one should consider when creating an SRv6 device configuration template. For a wider picture, please see the contributing new devices document.

The configuration template (in Jinja2 format) should be stored in the netsim/ansible/templates/srv6/ directory. The template file name is derived from the netlab_device_type or ansible_network_os variable (see Configuring BGP for details on how the platform name is used).

Tip

The <platform> is the value of the netlab_device_type or ansible_network_os variable.

Device Features

Add the following features.srv6 entries to a device YAML file (netsim/devices/<device>.yml) to indicate which SRv6 features the platform supports:

  • isis – device supports SRv6 with IS-IS

  • ospf – device supports SRv6 with OSPFv3

  • bgp – device supports BGP v4/v6 overlay over SRv6 (end.dt4/end.dt6)

  • vpn – device supports BGP L3VPN v4/v6 over SRv6

Node Attributes

The srv6 node dictionary is always present on nodes that have the srv6 module enabled. It contains the following attributes after transformation:

srv6.locator

An IPv6 prefix in CIDR notation (e.g., 5f00:0:1::/48), specified in lab topology or automatically allocated per-node from the SRv6 locator address pool (default 5F00::/16, based on the IANA-reserved range in RFC 9602).

Templates typically use srv6.locator to configure the SRv6 locator prefix:

locator {{ inventory_hostname }}
  prefix {{ srv6.locator }}

srv6.igp

A list of IGP protocol names (e.g., ['isis']) over which SRv6 should be signalled. The default is ['isis']. Valid values are isis and ospf.

Use if 'isis' in srv6.igp (or 'ospf' in srv6.igp) to conditionally enable SRv6 under an IGP:

{% if 'isis' in srv6.igp %}
router isis {{ isis.instance }}
  segment-routing srv6
    locator {{ inventory_hostname }}
{% endif %}

srv6.bgp

An optional dictionary with keys ipv4 and/or ipv6, each containing a list of BGP neighbor types that should use SRv6 as the transport for the plain IPv4 or IPv6 unicast address family (end.dt4/end.dt6, not VPN).

srv6.bgp is absent when the feature is disabled.

Example:

{% if srv6.bgp is defined %}
{%   for af in ['ipv4','ipv6'] if af in srv6.bgp %}
  family {{ af }}
    locator {{ inventory_hostname }}
{%   endfor %}
{% endif %}

srv6.vpn

A dictionary with keys ipv4 and/or ipv6, each containing a list of BGP neighbor types for which BGP L3VPN routes should be carried over SRv6 (end.dt4-vrf/end.dt6-vrf).

The structure and boolean-expansion rules are identical to srv6.bgp. srv6.vpn is absent when L3VPN is disabled.

srv6.transit_only

A boolean flag (True/False). When True, the node acts as a transit-only SRv6 node — it forwards SRv6 traffic but does not need to allocate FPE resources or end.dt SIDs for originating/terminating traffic. Default is False.

{% if not srv6.transit_only|default(False) %}
  termination-fpe: [2]
{% endif %}

Loopback IPv6 Address

loopback.ipv6 is always present on SRv6 nodes (enforced by node_post_transform). It may be user-defined, assigned from the loopback topology pool, or automatically assigned as the first host address in srv6.locator (when srv6.allocate_loopback: True).

Templates must use loopback.ipv6 as the SRv6 source address:

source-address {{ loopback.ipv6 | ansible.utils.ipaddr('address') }}

BGP Neighbor Attributes

The srv6 module modifies the bgp.neighbors list during node_post_transform. For each BGP neighbor that…

  • has an ipv6 transport address

  • has no ipv4 transport address,

  • is listed in srv6.bgp.ipv4 or srv6.vpn.ipv4 (i.e., IPv4 AF is carried over an IPv6 session)

…the module adds:

  • extended_nexthop (True) — signals that the BGP session requires extended next-hop encoding (RFC 8950) to carry IPv4 prefixes over an IPv6 transport session.

Templates could check for this attribute to conditionally enable extended next-hop negotiation:

{% for n in bgp.neighbors|default([]) if n.ipv6 is defined %}
{%   if n.extended_nexthop is defined %}
  neighbor {{ n.ipv6 }} capability extended-nexthop
{%   endif %}
{% endfor %}

Interface Attributes

The srv6 module does not add any per-interface attributes. Templates that need SRv6 interface-level configuration (e.g., end.x SIDs) typically iterate over interfaces that have IS-IS or OSPF enabled:

{% set srv6_interfaces = interfaces | selectattr('isis','defined') | list %}

Template Architecture

Complex platforms may split SRv6 configuration into a main template and a conditionally-included BGP sub-template. The main template handles locator declaration and IGP integration; the BGP sub-template handles the BGP overlay and VPN configuration.

Example (frr.j2 main template, simplified):

segment-routing
 srv6
  encapsulation
   source-address {{ loopback.ipv6 | ansible.utils.ipaddr('address') }}
  locators
   locator {{ inventory_hostname }}
    prefix {{ srv6.locator }}

{% if 'isis' in srv6.igp|default([]) and isis.instance is defined %}
router isis {{ isis.instance }}
 segment-routing srv6
   locator {{ inventory_hostname }}
{% endif %}

{% if srv6.vpn is defined and bgp.as is defined %}
{%   include "frr.bgp.j2" %}
{% endif %}

Example (frr.bgp.j2 BGP sub-template, simplified):

router bgp {{ bgp.as }}
 segment-routing srv6
  locator {{ inventory_hostname }}

{% if srv6.vpn is defined %}
{%   for n in bgp.neighbors|default([]) if n.ipv6 is defined %}
{%     if n.extended_nexthop is defined %}
 neighbor {{ n.ipv6 }} capability extended-nexthop
{%     endif %}
{%     for af in ['ipv4','ipv6'] if n.type in srv6.vpn.get(af,[]) %}
 address-family {{ af }} vpn
  neighbor {{ n.ipv6 }} activate
{%     endfor %}
{%   endfor %}
{% endif %}

Example (sros.j2, Nokia SR-OS — gNMI/YANG path style):

{% set srv6_interfaces = interfaces | selectattr('isis','defined') | list %}
updates:
- path: configure/router[router-name=Base]/segment-routing/segment-routing-v6
  val:
   locator:
   - locator-name: JvB
     prefix:
      ip-prefix: {{ srv6.locator }}
{%   if not srv6.transit_only|default(False) %}
     termination-fpe: [2]
{%   endif %}

{% if 'isis' in srv6.igp %}
- path: configure/router[router-name=Base]/isis[isis-instance=0]
  val:
   segment-routing-v6:
    admin-state: enable
    locator:
    - locator-name: JvB
{% endif %}

Integration Tests

The integration tests for the SRv6 module are in the tests/integration/srv6/ directory:

  • 02-isis-ipv4-bgp-vpn.yml — PE router running IS-IS + BGP L3VPN (srv6.vpn.ipv4: True) over an IPv6-only SRv6 core, with VRFs attached; validates end-to-end L3VPN reachability.

  • 12-isis-ipv6-bgp-vpn.yml — Similar scenario with IPv6 L3VPN overlay.

  • x-01-isis-ipv4-bgp.yml — PE router running IS-IS + BGP (srv6.bgp.ipv4: True) with allocate_loopback: True, carrying IPv4 over an IPv6-only SRv6 core (4PE scenario).

  • x-11-isis-ipv6-bgp.yml — Similar scenario with IPv6 BGP overlay.