Merge pull request #14810 from dmytroshytyi-6WIND/srv6_bgp_sid_reachability

SRv6 BGP SID reachability
This commit is contained in:
Russ White 2024-02-27 10:32:14 -05:00 committed by GitHub
commit c4f9b874b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 557 additions and 18 deletions

View File

@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
struct bgp_path_info *path)
{
return (bnc && (bnc->nexthop_num > 0 &&
(CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
bgp_isvalid_nexthop_for_mplsovergre(bnc, path))));
}
static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc,
struct bgp_path_info *path)
{
if (bgp_zebra_num_connects() == 0)
return 1;
if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) {
/* In the case of SRv6-VPN, we need to track the reachability to the
* SID (in other words, IPv6 address). We check that the SID is
* available in the BGP update; then if it is available, we check
* for the nexthop reachability.
*/
if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc)))
return 1;
return 0;
}
/*
* - In the case of MPLS-VPN, the label is learned from LDP or other
* In the case of MPLS-VPN, the label is learned from LDP or other
* protocols, and nexthop tracking is enabled for the label.
* The value is recorded as BGP_NEXTHOP_LABELED_VALID.
* - In the case of SRv6-VPN, we need to track the reachability to the
* SID (in other words, IPv6 address). As in MPLS, we need to record
* the value as BGP_NEXTHOP_SID_VALID. However, this function is
* currently not implemented, and this function assumes that all
* Transit routes for SRv6-VPN are valid.
* - Otherwise check for mpls-gre acceptance
*/
return (bgp_zebra_num_connects() == 0 ||
(bnc && (bnc->nexthop_num > 0 &&
(CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
bnc->bgp->srv6_enabled ||
bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
return bgp_isvalid_nexthop_for_mpls(bnc, path);
}
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
@ -496,7 +508,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
else if (safi == SAFI_UNICAST && pi &&
pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra &&
pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop)
return bgp_isvalid_nexthop_for_mpls(bnc, pi);
return bgp_isvalid_nexthop_for_l3vpn(bnc, pi);
else if (safi == SAFI_MPLS_VPN && pi &&
pi->sub_type != BGP_ROUTE_IMPORTED)
/* avoid not redistributing mpls vpn routes */
@ -1045,8 +1057,11 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
break;
case AFI_IP6:
p->family = AF_INET6;
if (is_bgp_static) {
if (pi->attr && pi->attr->srv6_l3vpn) {
IPV6_ADDR_COPY(&(p->u.prefix6),
&(pi->attr->srv6_l3vpn->sid));
p->prefixlen = IPV6_MAX_BITLEN;
} else if (is_bgp_static) {
p->u.prefix6 = p_orig->u.prefix6;
p->prefixlen = p_orig->prefixlen;
} else {
@ -1295,8 +1310,9 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
&& (path->attr->evpn_overlay.type
!= OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
bgp_isvalid_nexthop_for_mpls(bnc, path) ? true
: false;
bgp_isvalid_nexthop_for_l3vpn(bnc, path)
? true
: false;
} else if (safi == SAFI_MPLS_VPN &&
path->sub_type != BGP_ROUTE_IMPORTED) {
/* avoid not redistributing mpls vpn routes */

View File

@ -3207,6 +3207,31 @@ L3VPN SRv6
Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must
be set in zebra, but user can set it in any order.
L3VPN SRv6 SID reachability
---------------------------
In the context of IPv4 L3VPN over SRv6 specific usecase, 2001:db8:12::2
is the peer IPv6 address of r2, and 2001:db8:2:2:: is the SRv6 SID
advertised by router r2 for prefix P. On r1, the SID reachability is
checked in order to install the prefix P. The below output indicates
that the 2001:db8:2:2:: prefix is valid.
.. code-block:: frr
r1# show bgp nexthop detail
Current BGP nexthop cache:
2001:db8:2:2:: valid [IGP metric 0], #paths 4
gate 2001:db8:12::2, if eth0
Last update: Tue Nov 14 10:36:28 2023
Paths:
1/1 192.168.2.0/24 VRF vrf10 flags 0x4018
1/3 192.168.2.0/24 RD 65002:10 VRF default flags 0x418
2001:db8:12::2 valid [IGP metric 0], #paths 0, peer 2001:db8:12::2
if eth0
Last update: Tue Nov 14 10:36:26 2023
Paths:
General configuration
^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,4 @@
!
ip route 0.0.0.0/0 192.168.1.254
ipv6 route ::/0 2001:1::ffff
!

View File

@ -0,0 +1,6 @@
hostname c11
!
interface eth0
ip address 192.168.1.1/24
ipv6 address 2001:1::1/64
!

View File

@ -0,0 +1,4 @@
!
ip route 0.0.0.0/0 192.168.1.254
ipv6 route ::/0 2001:1::ffff
!

View File

@ -0,0 +1,6 @@
hostname c12
!
interface eth0
ip address 192.168.1.1/24
ipv6 address 2001:1::1/64
!

View File

@ -0,0 +1,4 @@
!
ip route 0.0.0.0/0 192.168.2.254
ipv6 route ::/0 2001:2::ffff
!

View File

@ -0,0 +1,6 @@
hostname c21
!
interface eth0
ip address 192.168.2.1/24
ipv6 address 2001:2::1/64
!

View File

@ -0,0 +1,5 @@
!
ip route 0.0.0.0/0 192.168.2.254
ipv6 route ::/0 2001:2::ffff
!

View File

@ -0,0 +1,9 @@
hostname c22
!
interface eth0
ip address 192.168.2.1/24
ipv6 address 2001:2::1/64
!
ip route 0.0.0.0/0 192.168.2.254
ipv6 route ::/0 2001:2::ffff
!

View File

@ -0,0 +1,4 @@
!
ip route 0.0.0.0/0 192.168.3.254
ipv6 route ::/0 2001:3::ffff
!

View File

@ -0,0 +1,6 @@
hostname c31
!
interface eth0
ip address 192.168.3.1/24
ipv6 address 2001:3::1/64
!

View File

@ -0,0 +1,4 @@
!
ip route 0.0.0.0/0 192.168.3.254
ipv6 route ::/0 2001:3::ffff
!

View File

@ -0,0 +1,6 @@
hostname c32
!
interface eth0
ip address 192.168.3.1/24
ipv6 address 2001:3::1/64
!

View File

@ -0,0 +1,61 @@
frr defaults traditional
!
hostname r1
password zebra
!
log commands
!
router bgp 65001
bgp router-id 192.0.2.1
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor 2001:db8:12::2 remote-as 65002
neighbor 2001:db8:12::2 timers 3 10
neighbor 2001:db8:12::2 timers connect 1
neighbor 2001:db8:12::2 capability extended-nexthop
neighbor 2001:db8:13::3 remote-as 65001
neighbor 2001:db8:13::3 timers 3 10
neighbor 2001:db8:13::3 timers connect 1
neighbor 2001:db8:13::3 capability extended-nexthop
!
segment-routing srv6
locator default
!
address-family ipv4 vpn
neighbor 2001:db8:12::2 activate
neighbor 2001:db8:13::3 activate
exit-address-family
!
!
router bgp 65001 vrf vrf10
bgp router-id 192.0.2.1
!
address-family ipv4 unicast
redistribute connected
sid vpn export 1
rd vpn export 65001:10
rt vpn both 0:10
import vpn
export vpn
exit-address-family
!
!
router bgp 65001 vrf vrf20
bgp router-id 192.0.2.1
!
address-family ipv4 unicast
redistribute connected
sid vpn export 2
rd vpn export 65001:20
rt vpn both 0:20
import vpn
export vpn
exit-address-family
!
!
interface eth0
mpls bgp forwarding
!
interface eth1
mpls bgp forwarding
!

View File

@ -0,0 +1,4 @@
!
ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
ipv6 route 2001:db8:3:3::/64 2001:db8:13::3
!

View File

@ -0,0 +1,32 @@
log file zebra.log
!
hostname r1
!
interface lo
ipv6 address 2001:db8:1:1::1/128
!
interface eth0
ipv6 address 2001:db8:12::1/64
!
interface eth1
ipv6 address 2001:db8:13::1/64
!
interface eth2 vrf vrf10
ip address 192.168.1.254/24
!
interface eth3 vrf vrf20
ip address 192.168.1.254/24
!
segment-routing
srv6
locators
locator default
prefix 2001:db8:1:1::/64
!
!
!
ip forwarding
ipv6 forwarding
!
line vty
!

View File

@ -0,0 +1,50 @@
frr defaults traditional
!
hostname r2
password zebra
!
log commands
!
router bgp 65002
bgp router-id 192.0.2.2
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor 2001:db8:12::1 remote-as 65001
neighbor 2001:db8:12::1 timers 3 10
neighbor 2001:db8:12::1 timers connect 1
neighbor 2001:db8:12::1 capability extended-nexthop
!
segment-routing srv6
locator default
!
address-family ipv4 vpn
neighbor 2001:db8:12::1 activate
exit-address-family
!
!
router bgp 65002 vrf vrf10
bgp router-id 192.0.2.2
!
address-family ipv4 unicast
redistribute connected
sid vpn export 1
rd vpn export 65002:10
rt vpn both 0:10
import vpn
export vpn
exit-address-family
!
!
router bgp 65002 vrf vrf20
bgp router-id 192.0.2.2
!
address-family ipv4 unicast
redistribute connected
sid vpn export 2
rd vpn export 65002:20
rt vpn both 0:20
import vpn
export vpn
exit-address-family
!
!

View File

@ -0,0 +1,4 @@
!
ipv6 route 2001:db8:1:1::/64 2001:db8:12::1
ipv6 route 2001:db8:3:3::/64 2001:db8:12::1
!

View File

@ -0,0 +1,29 @@
log file zebra.log
!
hostname r2
!
interface lo
ipv6 address 2001:db8:2:2::1/128
!
interface eth0
ipv6 address 2001:db8:12::2/64
!
interface eth1 vrf vrf10
ip address 192.168.2.254/24
!
interface eth2 vrf vrf20
ip address 192.168.2.254/24
!
segment-routing
srv6
locators
locator default
prefix 2001:db8:2:2::/64
!
!
!
ip forwarding
ipv6 forwarding
!
line vty
!

View File

@ -0,0 +1,50 @@
frr defaults traditional
!
hostname r2
password zebra
!
log commands
!
router bgp 65001
bgp router-id 192.0.2.3
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor 2001:db8:13::1 remote-as 65001
neighbor 2001:db8:13::1 timers 3 10
neighbor 2001:db8:13::1 timers connect 1
neighbor 2001:db8:13::1 capability extended-nexthop
!
segment-routing srv6
locator default
!
address-family ipv4 vpn
neighbor 2001:db8:13::1 activate
exit-address-family
!
!
router bgp 65001 vrf vrf10
bgp router-id 192.0.2.3
!
address-family ipv4 unicast
redistribute connected
sid vpn export 1
rd vpn export 65001:10
rt vpn both 0:10
import vpn
export vpn
exit-address-family
!
!
router bgp 65001 vrf vrf20
bgp router-id 192.0.2.2
!
address-family ipv4 unicast
redistribute connected
sid vpn export 2
rd vpn export 65001:20
rt vpn both 0:20
import vpn
export vpn
exit-address-family
!
!

View File

@ -0,0 +1,6 @@
!
ipv6 route 2001:db8:12::/64 2001:db8:13::1
!
ipv6 route 2001:db8:1:1::/64 2001:db8:13::1
ipv6 route 2001:db8:2:2::/64 2001:db8:13::1
!

View File

@ -0,0 +1,29 @@
log file zebra.log
!
hostname r2
!
interface lo
ipv6 address 2001:db8:3:3::1/128
!
interface eth0
ipv6 address 2001:db8:13::3/64
!
interface eth1 vrf vrf10
ip address 192.168.3.254/24
!
interface eth2 vrf vrf20
ip address 192.168.3.254/24
!
segment-routing
srv6
locators
locator default
prefix 2001:db8:3:3::/64
!
!
!
ip forwarding
ipv6 forwarding
!
line vty
!

View File

@ -0,0 +1,169 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
#
# Part of NetDEF Topology Tests
#
# Copyright (c) 2023 by 6WIND
#
import os
import re
import sys
import json
import functools
import pytest
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from lib.common_config import required_linux_kernel_version
from lib.checkping import check_ping
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
def build_topo(tgen):
tgen.add_router("r1")
tgen.add_router("r2")
tgen.add_router("r3")
tgen.add_router("c11")
tgen.add_router("c12")
tgen.add_router("c21")
tgen.add_router("c22")
tgen.add_router("c31")
tgen.add_router("c32")
tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0")
tgen.add_link(tgen.gears["r1"], tgen.gears["r3"], "eth1", "eth0")
tgen.add_link(tgen.gears["r1"], tgen.gears["c11"], "eth2", "eth0")
tgen.add_link(tgen.gears["r1"], tgen.gears["c12"], "eth3", "eth0")
tgen.add_link(tgen.gears["r2"], tgen.gears["c21"], "eth1", "eth0")
tgen.add_link(tgen.gears["r2"], tgen.gears["c22"], "eth2", "eth0")
tgen.add_link(tgen.gears["r3"], tgen.gears["c31"], "eth1", "eth0")
tgen.add_link(tgen.gears["r3"], tgen.gears["c32"], "eth2", "eth0")
def setup_module(mod):
result = required_linux_kernel_version("5.15")
if result is not True:
pytest.skip("Kernel requirements are not met")
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
tgen.gears["r1"].run("ip link set vrf10 up")
tgen.gears["r1"].run("ip link add vrf20 type vrf table 20")
tgen.gears["r1"].run("ip link set vrf20 up")
tgen.gears["r1"].run("ip link set eth2 master vrf10")
tgen.gears["r1"].run("ip link set eth3 master vrf20")
tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1")
tgen.gears["r2"].run("ip link add vrf10 type vrf table 10")
tgen.gears["r2"].run("ip link set vrf10 up")
tgen.gears["r2"].run("ip link add vrf20 type vrf table 20")
tgen.gears["r2"].run("ip link set vrf20 up")
tgen.gears["r2"].run("ip link set eth1 master vrf10")
tgen.gears["r2"].run("ip link set eth2 master vrf20")
tgen.gears["r3"].run("sysctl net.vrf.strict_mode=1")
tgen.gears["r3"].run("ip link add vrf10 type vrf table 10")
tgen.gears["r3"].run("ip link set vrf10 up")
tgen.gears["r3"].run("ip link add vrf20 type vrf table 20")
tgen.gears["r3"].run("ip link set vrf20 up")
tgen.gears["r3"].run("ip link set eth1 master vrf10")
tgen.gears["r3"].run("ip link set eth2 master vrf20")
tgen.start_router()
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
def test_ping():
tgen = get_topogen()
check_ping("c11", "192.168.2.1", True, 10, 1)
check_ping("c11", "192.168.3.1", True, 10, 1)
check_ping("c12", "192.168.2.1", True, 10, 1)
check_ping("c12", "192.168.3.1", True, 10, 1)
check_ping("c21", "192.168.3.1", True, 10, 1)
check_ping("c22", "192.168.3.1", True, 10, 1)
def test_sid_unreachable_nht():
get_topogen().gears["r1"].vtysh_cmd(
"""
configure terminal
no ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
"""
)
check_ping("c11", "192.168.2.1", False, 10, 1)
def test_sid_reachable_again_nht():
get_topogen().gears["r1"].vtysh_cmd(
"""
configure terminal
ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
"""
)
check_ping("c11", "192.168.2.1", True, 10, 1)
def test_sid_unreachable_bgp_update():
get_topogen().gears["r2"].vtysh_cmd(
"""
configure terminal
router bgp 65002
no segment-routing srv6
exit
router bgp 65002 vrf vrf10
address-family ipv4 unicast
no sid vpn export 1
"""
)
check_ping("c11", "192.168.2.1", False, 10, 1)
def test_sid_reachable_again_bgp_update():
get_topogen().gears["r2"].vtysh_cmd(
"""
configure terminal
router bgp 65002
segment-routing srv6
locator default
exit
exit
router bgp 65002 vrf vrf10
address-family ipv4 unicast
sid vpn export 1
"""
)
check_ping("c11", "192.168.2.1", True, 10, 1)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))