Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bgpd: Fix announce SRv6 locally-generated routes to Zebra #12551

Merged
merged 2 commits into from
Dec 23, 2022
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
16 changes: 11 additions & 5 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1532,20 +1532,26 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,

api_nh->weight = nh_weight;

if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid) &&
if (mpinfo->extra &&
bgp_is_valid_label(&mpinfo->extra->label[0]) &&
!sid_zero(&mpinfo->extra->sid[0].sid) &&
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
sid_info = &mpinfo->extra->sid[0];

memcpy(&api_nh->seg6_segs, &sid_info->sid,
sizeof(api_nh->seg6_segs));

if (sid_info->transposition_len != 0) {
if (!bgp_is_valid_label(
&mpinfo->extra->label[0]))
continue;

mpls_lse_decode(mpinfo->extra->label[0], &label,
&ttl, &exp, &bos);

if (label < MPLS_LABEL_UNRESERVED_MIN) {
if (bgp_debug_zebra(&api.prefix))
zlog_debug(
"skip invalid SRv6 routes: transposition scheme is used, but label is too small");
continue;
}

transpose_sid(&api_nh->seg6_segs, label,
sid_info->transposition_offset,
sid_info->transposition_len);
Expand Down
Empty file.
9 changes: 9 additions & 0 deletions tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
log file zebra.log
!
hostname ce1
!
interface eth0
ip address 172.16.0.1/24
!
line vty
!
41 changes: 41 additions & 0 deletions tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
frr defaults traditional
!
hostname pe1
password zebra
!
log stdout notifications
log monitor notifications
log commands
!
router bgp 65001
bgp router-id 192.0.2.1
!
segment-routing srv6
locator default
exit
!
!
router bgp 65001 vrf vrf10
bgp router-id 192.0.2.1
!
address-family ipv4 unicast
redistribute connected
sid vpn export auto
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
rd vpn export 65001:20
rt vpn both 0:10
import vpn
export vpn
exit-address-family
!
!
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"vrfName": "default",
"routerId": "192.0.2.1",
"localAS": 65001,
"routes": {
"routeDistinguishers": {
"65001:10": {
"172.16.0.0/24": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"prefix": "172.16.0.0",
"prefixLen": 24,
"network": "172.16.0.0\/24",
"origin": "incomplete",
"announceNexthopSelf": true,
"nhVrfName": "vrf10",
"nexthops": [
{
"hostname": "pe1",
"afi": "ipv4",
"used": true
}
]
}
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"vrfName": "vrf10",
"routerId": "192.0.2.1",
"localAS": 65001,
"routes": {
"172.16.0.0/24": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"prefix": "172.16.0.0",
"prefixLen": 24,
"network": "172.16.0.0\/24",
"origin": "incomplete",
"nexthops": [
{
"hostname": "pe1",
"afi": "ipv4",
"used": true
}
]
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"172.16.0.0\/24": [
{
"prefix": "172.16.0.0\/24",
"prefixLen": 24,
"protocol": "bgp",
"vrfName": "vrf20",
"selected": true,
"destSelected": true,
"installed": true,
"nexthops": [
{
"fib": true,
"directlyConnected": true,
"interfaceName": "eth0",
"vrf": "vrf10",
"active": true
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"vrfName": "vrf20",
"routerId": "192.0.2.1",
"localAS": 65001,
"routes": {
"172.16.0.0/24": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"prefix": "172.16.0.0",
"prefixLen": 24,
"network": "172.16.0.0\/24",
"origin": "incomplete",
"announceNexthopSelf": true,
"nhVrfName": "vrf10",
"nexthops": [
{
"hostname": "pe1",
"afi": "ipv4",
"used": true
}
]
}
]
}
}
27 changes: 27 additions & 0 deletions tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
log file zebra.log
!
hostname pe1
!
interface lo
ip address 10.0.0.1/32
!
interface eth0 vrf vrf10
ip address 172.16.0.254/24
!
line vty
!
segment-routing
srv6
locators
locator default
prefix 2001:db8:2::/64 block-len 40 node-len 24 func-bits 16
exit
!
exit
!
exit
!
exit
!
end
!
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python

# Copyright (c) 2022, LINE Corporation
# Authored by Ryoga Saito <ryoga.saito@linecorp.com>
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#

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

pytestmark = [pytest.mark.bgpd]


def build_topo(tgen):
tgen.add_router("pe1")
tgen.add_router("ce1")

tgen.add_link(tgen.gears["pe1"], tgen.gears["ce1"], "eth0", "eth0")


def setup_module(mod):
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_BGP,
os.path.join(CWD, '{}/bgpd.conf'.format(rname)))

tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10")
tgen.gears["pe1"].run("ip link set vrf10 up")
tgen.gears["pe1"].run("ip link add vrf20 type vrf table 20")
tgen.gears["pe1"].run("ip link set vrf20 up")
tgen.gears["pe1"].run("ip link set eth0 master vrf10")

tgen.start_router()


def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()


def open_json_file(path):
try:
with open(path, "r") as f:
return json.load(f)
except IOError:
assert False, "Could not read file {}".format(path)


def check(name, command, checker):
tgen = get_topogen()
router = tgen.gears[name]

def _check():
try:
return checker(router.vtysh_cmd(command))
except:
return False

logger.info('[+] check {} "{}"'.format(name, command))
_, result = topotest.run_and_expect(_check, None, count=10, wait=0.5)
assert result is None, "Failed"


def check_vrf10_bgp_rib(output):
expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD)
actual = json.loads(output)
return topotest.json_cmp(actual, expected)


def check_default_bgp_vpn_rib(output):
expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD)
actual = json.loads(output)
return topotest.json_cmp(actual, expected)


def check_vrf20_bgp_rib(output):
expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD)
actual = json.loads(output)
return topotest.json_cmp(actual, expected)


def check_vrf20_rib(output):
expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD)
actual = json.loads(output)
return topotest.json_cmp(actual, expected)


def test_rib():
check("pe1", "show bgp vrf vrf10 ipv4 unicast json", check_vrf10_bgp_rib)
check("pe1", "show bgp ipv4 vpn json", check_default_bgp_vpn_rib)
check("pe1", "show bgp vrf vrf20 ipv4 unicast json", check_vrf20_bgp_rib)
check("pe1", "show ip route vrf vrf20 json", check_vrf20_rib)


if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))