Skip to content

Commit

Permalink
Merge pull request FRRouting#17608 from opensourcerouting/fix/vpn_imp…
Browse files Browse the repository at this point in the history
…ort_routes_allowas-in

bgpd: Import allowed routes with self AS if desired
  • Loading branch information
riw777 authored Dec 10, 2024
2 parents c05c2b1 + 3d89c67 commit 3f6bf6d
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 2 deletions.
9 changes: 7 additions & 2 deletions bgpd/bgp_mplsvpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2167,6 +2167,8 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct interface *ifp = NULL;
char rd_buf[RD_ADDRSTRLEN];
struct aspath *new_aspath;
int32_t aspath_loop_count = 0;
struct peer *peer = path_vpn->peer;

int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);

Expand Down Expand Up @@ -2227,7 +2229,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);

/* Check if leaked route has our asn. If so, don't import it. */
if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) {
if (CHECK_FLAG(peer->af_flags[afi][SAFI_MPLS_VPN], PEER_FLAG_ALLOWAS_IN))
aspath_loop_count = peer->allowas_in[afi][SAFI_MPLS_VPN];
if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as) > aspath_loop_count) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->vrfleak &&
Expand Down Expand Up @@ -2513,11 +2517,12 @@ void vpn_leak_to_vrf_update(struct bgp *from_bgp,
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);

int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);

if (debug)
zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn);
zlog_debug("%s: start (path_vpn=%p, prefix=%pFX)", __func__, path_vpn, p);

/* Loop over VRFs */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
Expand Down
Empty file.
30 changes: 30 additions & 0 deletions tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
!
interface r1-eth0
ip address 192.168.179.4/24
exit
!
router bgp 65001
bgp router-id 192.168.179.4
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.179.5 remote-as auto
!
address-family ipv4 vpn
neighbor 192.168.179.5 activate
neighbor 192.168.179.5 next-hop-self
neighbor 192.168.179.5 allowas-in 1
exit-address-family
!
router bgp 65001 vrf CUSTOMER-A
bgp router-id 192.168.0.1
no bgp ebgp-requires-policy
no bgp network import-check
!
address-family ipv4 unicast
label vpn export auto
rd vpn export 100:1
rt vpn both 100:1
export vpn
import vpn
exit-address-family

40 changes: 40 additions & 0 deletions tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
!
interface lo
ip address 10.10.10.10/32
!
interface r2-eth0
ip address 192.168.179.5/24
exit
!
interface r2-eth1
ip address 192.168.2.2/24
exit
!
router bgp 65002
bgp router-id 192.168.179.5
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.179.4 remote-as auto
!
address-family ipv4 vpn
neighbor 192.168.179.4 activate
neighbor 192.168.179.4 next-hop-self
exit-address-family
!
router bgp 65002 vrf CUSTOMER-A
bgp router-id 192.168.0.2
no bgp ebgp-requires-policy
no bgp network import-check
!
address-family ipv4 unicast
redistribute connected
network 10.10.10.10/32 route-map r1
label vpn export auto
rd vpn export 100:1
rt vpn both 100:1
export vpn
import vpn
exit-address-family
!
route-map r1 permit 10
set as-path prepend 65001
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC

#
# Copyright (c) 2024 by
# Donatas Abraitis <donatas@opensourcerouting.org>
#

import os
import sys
import json
import pytest
import functools

CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))

# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, get_topogen

pytestmark = [pytest.mark.bgpd]


def build_topo(tgen):
tgen.add_router("r1")
tgen.add_router("r2")

switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])

switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r1"])

switch = tgen.add_switch("s3")
switch.add_link(tgen.gears["r2"])


def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()

r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]

r1.run("ip link add CUSTOMER-A type vrf table 1001")
r1.run("ip link set up dev CUSTOMER-A")
r1.run("ip link set r1-eth1 master CUSTOMER-A")

r2.run("ip link add CUSTOMER-A type vrf table 1001")
r2.run("ip link set up dev CUSTOMER-A")
r2.run("ip link set r2-eth1 master CUSTOMER-A")

router_list = tgen.routers()

for _, (rname, router) in enumerate(router_list.items(), 1):
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))

tgen.start_router()


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


def test_issue_12502():
tgen = get_topogen()

if tgen.routers_have_failure():
pytest.skip(tgen.errors)

r1 = tgen.gears["r1"]

def _bgp_converge():
output = json.loads(
r1.vtysh_cmd("show bgp vrf CUSTOMER-A ipv4 unicast 10.10.10.10/32 json")
)
expected = {
"paths": [
{
"importedFrom": "100:1",
"aspath": {
"string": "65002 65001",
},
"valid": True,
}
]
}
return topotest.json_cmp(output, expected)

test_func = functools.partial(_bgp_converge)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Failed to see 192.168.2.0/24 with a valid next-hop"

def _vrf_route_imported_to_zebra():
output = json.loads(
r1.vtysh_cmd("show ip route vrf CUSTOMER-A 10.10.10.10/32 json")
)
expected = {
"10.10.10.10/32": [
{
"protocol": "bgp",
"vrfName": "CUSTOMER-A",
"selected": True,
"installed": True,
"table": 1001,
"internalNextHopNum": 1,
"internalNextHopActiveNum": 1,
"nexthops": [
{
"fib": True,
"ip": "192.168.179.5",
"afi": "ipv4",
"interfaceName": "r1-eth0",
"vrf": "default",
"active": True,
}
],
}
]
}
return topotest.json_cmp(output, expected)

test_func = functools.partial(_vrf_route_imported_to_zebra)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert (
result is None
), "Failed to see 10.10.10.10/32 to be imported into default VRF (Zebra)"


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

0 comments on commit 3f6bf6d

Please sign in to comment.