Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions docs/module/srv6.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ Supported SRv6 features:

* End SIDs (nodes) and End-x SIDs (links), all statically allocated
* IS-IS routing protocol with SRv6 TLVs
* BGP L3VPN v4/v6 over SRv6
* SRv6 transport for global IPv4/IPv6 BGP routes
* BGP IPv4/IPv6 L3VPN over SRv6

The module currently depends on IS-IS and will trigger a configuration error if the **isis** module is not enabled in the network topology. It is initially focused on the L3VPN use case; IPv4 islands over SRv6 or IPv6 transport between SRv6 endpoints will be added once FRRouting supports them.

## Platform Support
The following table describes the per-platform support of individual router-level SRv6 features:

| Operating system | IS-IS | OSPFv3 | BGP v4/v6 | Transit only |
|--------------------|:--:|:-:|:-:|:-:|
| Operating system | IS-IS | OSPFv3 | BGP v4/v6 | Transit only |
|--------------------|:--:|:-:|:-:| :-:|
| Cisco IOS XE[^XE] | ✅ | ❌ | ❌ | ❌ |
| Cisco IOS XR[^XR] | ✅ | ❌ | ❌ | ❌ |
| FRR | ✅ | ❌ | | ❌ |
| FRR | ✅ | ❌ | | ❌ |
| Nokia SR OS[^SROS] | ✅ | ❌ | ✅ | ✅ |

[^SROS]: Includes the Nokia SR-SIM container and the Virtualized 7750 SR and 7950 XRS Simulator (vSIM) virtual machine
Expand Down Expand Up @@ -60,7 +61,7 @@ The following table describes the per-platform support of individual router-leve

This module provides 2 parameters that are identical in structure, controlling different BGP address families:

* **srv6.bgp** -- Controls IPv4 and IPv6 address families
* **srv6.bgp** -- Controls SRv6 next hops for global IPv4 and IPv6 BGP routes
* **srv6.vpn** -- Controls VPNv4 and VPNv6 address families

Each parameter could be a boolean (*True* to enable both IP address families on IBGP sessions), or a dictionary of parameters:
Expand All @@ -74,4 +75,4 @@ Each parameter could be a boolean (*True* to enable both IP address families on
* Boolean value *True* to enable the address family on IBGP sessions
* A string or a list of *ibgp/ebgp* keywords

For a tested example, see the [IPv4 L3VPN over SRv6 topology](https://github.com/ipspace/netlab/tree/dev/tests/integration/srv6/02-isis-ipv4-bgp-vpn.yml).
For a tested example, see the [SRv6 integration tests](https://github.com/ipspace/netlab/tree/dev/tests/integration/srv6).
27 changes: 16 additions & 11 deletions netsim/ansible/templates/srv6/frr.bgp.j2
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ router bgp {{ bgp.as }}
{% macro bgp_neighbor(n,peer,af) %}
neighbor {{ peer }} activate
neighbor {{ peer }} send-community both
neighbor {{ peer }} encapsulation-srv6
{% if n.next_hop_unchanged is defined %}
neighbor {{ peer }} attribute-unchanged next-hop
{% endif %}
Expand All @@ -19,35 +20,39 @@ router bgp {{ bgp.as }}
{% endif %}
{% endmacro -%}

{% if srv6.vpn is defined %}
{% for n in bgp.neighbors|default([]) if n.ipv6 is defined %}
{% if srv6.vpn|default(False) or srv6.bgp|default(False) %}
{% for n in bgp.neighbors|default([]) if n.ipv6 is defined and n.type == 'ibgp' %}
Comment thread
ipspace marked this conversation as resolved.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If this is limited to IBGP neighbors, we should probably document that more explicitly

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Will do. Thank you.

{% set peer = n.ipv6 %}
neighbor {{ peer }} remote-as {{ n.as }}
neighbor {{ peer }} description {{ n.name }} (SRv6)
{% if n.extended_nexthop is defined %}
neighbor {{ peer }} capability extended-nexthop
{% endif %}

{%- for af in ['ipv4','ipv6'] %}
{% if n.type in srv6.vpn.get(af,[]) %}
{% if srv6.bgp is defined and n.type in srv6.bgp.get(af,[]) %}
address-family {{ af }} unicast
!
sid export auto
{{ bgp_neighbor(n,peer,af) -}}
{% endif %}
{% if n.type in srv6.vpn[af]|default('') %}
address-family {{ af }} vpn
!
{{ bgp_neighbor(n,peer,af) -}}
{% endif %}
{% endfor %}
{% endfor %}
!
{% if vrfs is defined %}
{% for vname,vdata in vrfs.items() %}
{% endif %}
{% if srv6.vpn|default(False) and vrfs is defined %}
{% for vname,vdata in vrfs.items() %}
router bgp {{ vdata.as|default(bgp.as) }} vrf {{ vname }}
sid vpn per-vrf export auto
no bgp network import-check

{% for af in ['ipv4','ipv6'] if 'ebgp' in srv6.vpn.get(af,[]) %}
{% for af in ['ipv4','ipv6'] if 'ebgp' in srv6.vpn.get(af,[]) %}
address-family {{ af }} unicast
nexthop vpn export {{ loopback.ipv6|ansible.utils.ipaddr('address') }}
{% endfor %}
!
{% endfor %}
{% endif %}
!
{% endfor %}
{% endif %}
17 changes: 14 additions & 3 deletions netsim/ansible/templates/srv6/frr.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,23 @@
set -e

export SRv6_DEV="sr0"
export SRv6_VRF_DEV="vrf-srv6"

if [ ! -e /sys/devices/virtual/net/${SRv6_DEV} ]; then
ip link add ${SRv6_DEV} type dummy
ip link set ${SRv6_DEV} up
ip link add ${SRv6_DEV} type dummy
ip link set ${SRv6_DEV} up
fi

{% if 'bgp' in srv6.igp|default([]) or srv6.bgp|default(False) %}
#
# Create SRv6 default VRF, needed to install SRv6 nexthops
#
if [ ! -e /sys/devices/virtual/net/${SRv6_VRF_DEV} ]; then
ip link add ${SRv6_VRF_DEV} type vrf table 254
ip link set ${SRv6_VRF_DEV} up
fi
{% endif %}

# See https://onvox.net/2024/12/16/srv6-frr/
sysctl -w net.ipv6.seg6_flowlabel=1
sysctl -w net.ipv6.conf.all.seg6_enabled=1
Expand Down Expand Up @@ -44,7 +55,7 @@ router isis {{ isis.instance }}
exit
{% endif %}

{% if srv6.vpn is defined and bgp.as is defined %}
{% if (srv6.vpn|default(False) or srv6.bgp|default(False)) and bgp.as is defined %}
{% include "frr.bgp.j2" %}
{% endif %}

Expand Down
2 changes: 1 addition & 1 deletion netsim/devices/frr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ features:
af: [ ipv4, ipv6 ]
protocol: [ isis, ospfv2 ]
srv6:
bgp: false
bgp: true
isis: true
vpn: true
stp:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ message: |
two IPv4-only networks. The validation test checks end-to-end IPv4 connectivity across a SRv6 core.
See https://www.ietf.org/archive/id/draft-mishra-idr-v4-islands-v6-core-4pe-06.html

defaults.sources.extra: [ ../wait_times.yml ]
defaults.sources.extra: [ ../wait_times.yml, ../warnings.yml ]

addressing:
core:
Expand All @@ -19,7 +19,7 @@ addressing:
ipv4: 192.168.0.0/24
prefix: 32

srv6.allocate_loopback: True # Override the ipv6 loopback address and allocate one from the per-node locator range
srv6.allocate_loopback: False # Keep loopback interface outside of SRv6 SID
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We may want to remove this knob altogether, I initially thought this was a good idea but it does not solve the chicken-and-egg routing problem and mainly causes confusion


srv6.bgp:
ipv4: True # Enable IPv4 in the overlay (for IBGP)
Expand All @@ -42,7 +42,6 @@ groups:
core:
members: [ p ]
module: [ isis ]
srv6.bgp: False
ce:
members: [ ce1, ce2 ]
module: [ bgp ]
Expand Down Expand Up @@ -72,15 +71,15 @@ links:

validate:
isis_dut:
description: Check ISIS sessions with DUT (wait up to 30 seconds)
wait: 30
description: Check ISIS sessions with DUT
wait: isis_adj_p2p
wait_msg: Waiting for ISIS adjacency
nodes: [ p ]
plugin: isis_neighbor('dut',level='L2',area='49.0001')
stop_on_error: true
isis_pe2:
description: Check ISIS sessions with PE2 (wait up to 30 seconds)
wait: 30
description: Check ISIS sessions with PE2
wait: isis_adj_p2p
wait_msg: Waiting for ISIS adjacency
nodes: [ p ]
plugin: isis_neighbor('pe2',level='L2',area='49.0001')
Expand All @@ -99,26 +98,26 @@ validate:
plugin: bgp_neighbor(node.bgp.neighbors,'pe2',af='ipv4')
ibgp:
description: Check IBGP session with activation of IPv4 over IPv6
wait: 10
wait: ibgp_session
wait_msg: Waiting for IBGP sessions to start
nodes: [ pe2 ]
plugin: bgp_neighbor(node.bgp.neighbors,'dut',af='ipv6',activate='ipv4')
stop_on_error: true
ping_hh:
description: Ping-based host-to-host reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping_long
nodes: [ h1 ]
plugin: ping('h2')
ping_h_ce:
description: Ping-based host-to-CE reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping
nodes: [ h1, h2 ]
plugin: ping('ce1')
ping_ce_ce:
description: Ping-based CE-to-CE reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping
nodes: [ ce1 ]
plugin: ping(nodes.ce2.loopback.ipv4,src=nodes.ce1.loopback.ipv4)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ message: |
two IPv4-only networks. The validation test checks end-to-end IPv4 connectivity across a SRv6 core.
See https://www.ietf.org/archive/id/draft-mishra-idr-v4-islands-v6-core-4pe-06.html

defaults.sources.extra: [ ../wait_times.yml ]
defaults.sources.extra: [ ../wait_times.yml, ../warnings.yml ]

addressing:
core:
Expand All @@ -27,7 +27,7 @@ addressing:
ipv4: False
ipv6: 2001:db8:42::/48

srv6.allocate_loopback: True # Override the ipv6 loopback address and allocate one from the per-node locator range
srv6.allocate_loopback: False # Keep loopback interface outside of SRv6 SID

srv6.bgp:
ipv4: False # Enable IPv4 in the overlay (for IBGP)
Expand Down Expand Up @@ -56,7 +56,7 @@ groups:
module: [ bgp ]
loopback.pool: lb_ce
x_switches:
members: [ pe2 ]
members: [ p, pe2, ce1, ce2 ]
device: frr
provider: clab

Expand All @@ -80,15 +80,15 @@ links:

validate:
isis_dut:
description: Check ISIS sessions with DUT (wait up to 30 seconds)
wait: 30
description: Check ISIS sessions with DUT
wait: isis_adj_p2p
wait_msg: Waiting for ISIS adjacency
nodes: [ p ]
plugin: isis_neighbor('dut',level='L2',area='49.0001')
stop_on_error: true
isis_pe2:
description: Check ISIS sessions with PE2 (wait up to 30 seconds)
wait: 30
description: Check ISIS sessions with PE2
wait: isis_adj_p2p
wait_msg: Waiting for ISIS adjacency
nodes: [ p ]
plugin: isis_neighbor('pe2',level='L2',area='49.0001')
Expand All @@ -107,26 +107,26 @@ validate:
plugin: bgp_neighbor(node.bgp.neighbors,'pe2',af='ipv6')
ibgp:
description: Check IBGP session with activation of IPv4 over IPv6
wait: 10
wait: ibgp_session
wait_msg: Waiting for IBGP sessions to start
nodes: [ pe2 ]
plugin: bgp_neighbor(node.bgp.neighbors,'dut',af='ipv6')
stop_on_error: true
ping_hh:
description: Ping-based host-to-host reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping_long
nodes: [ h1 ]
plugin: ping('h2',af='ipv6')
ping_h_ce:
description: Ping-based host-to-CE reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping
nodes: [ h1, h2 ]
plugin: ping('ce1',af='ipv6')
ping_ce_ce:
description: Ping-based CE-to-CE reachability test
wait_msg: We might have to wait a bit longer
wait: 10
wait: ping
nodes: [ ce1 ]
plugin: ping(nodes.ce2.loopback.ipv6,src=nodes.ce1.loopback.ipv6,af='ipv6')
Loading