Merge pull request #15255 from louis-6wind/bgp-leak-interface

bgpd: fix interface of routes leaked from another VRF
This commit is contained in:
Donald Sharp 2024-02-08 11:18:58 -05:00 committed by GitHub
commit afa07a7f3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 354 additions and 16 deletions

View File

@ -2209,12 +2209,22 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/* If the path has accept-own community and the source VRF /* If the path has accept-own community and the source VRF
* is valid, reset next-hop to self, to allow importing own * is valid, reset next-hop to self, to allow importing own
* routes between different VRFs on the same node. * routes between different VRFs on the same node.
* Set the nh ifindex to VRF's interface, not the real interface. */
if (src_bgp)
subgroup_announce_reset_nhop(nhfamily, &static_attr);
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
/* The nh ifindex may not be defined (when the route is
* imported from the network statement => BGP_ROUTE_STATIC)
* or to the real interface.
* Rewrite the nh ifindex to VRF's interface.
* Let the kernel to decide with double lookup the real next-hop * Let the kernel to decide with double lookup the real next-hop
* interface when installing the route. * interface when installing the route.
*/ */
if (src_bgp) { if (src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC ||
subgroup_announce_reset_nhop(nhfamily, &static_attr); bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) {
ifp = if_get_vrf_loopback(src_vrf->vrf_id); ifp = if_get_vrf_loopback(src_vrf->vrf_id);
if (ifp) if (ifp)
static_attr.nh_ifindex = ifp->ifindex; static_attr.nh_ifindex = ifp->ifindex;
@ -2300,9 +2310,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
*/ */
if (!CHECK_FLAG(to_bgp->af_flags[afi][safi], if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) { BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
/* work back to original route */
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
/* /*
* if original route was unicast, * if original route was unicast,
* then it did not arrive over vpn * then it did not arrive over vpn

View File

@ -12,7 +12,7 @@
{ {
"fib": true, "fib": true,
"directlyConnected": true, "directlyConnected": true,
"interfaceName": "eth0", "interfaceName": "vrf10",
"vrf": "vrf10", "vrf": "vrf10",
"active": true "active": true
} }

View File

@ -1,10 +1,19 @@
hostname r1 hostname r1
router bgp 99
no bgp ebgp-requires-policy
address-family ipv4 unicast
redistribute connected
import vrf DONNA
!
!
router bgp 99 vrf DONNA router bgp 99 vrf DONNA
no bgp ebgp-requires-policy no bgp ebgp-requires-policy
address-family ipv4 unicast address-family ipv4 unicast
redistribute connected redistribute connected
import vrf EVA import vrf EVA
import vrf NOTEXISTING
import vrf default
! !
! !
router bgp 99 vrf EVA router bgp 99 vrf EVA
@ -12,5 +21,13 @@ router bgp 99 vrf EVA
address-family ipv4 unicast address-family ipv4 unicast
redistribute connected redistribute connected
import vrf DONNA import vrf DONNA
import vrf NOTEXISTING
!
!
router bgp 99 vrf NOTEXISTING
no bgp ebgp-requires-policy
no bgp network import-check
address-family ipv4 unicast
network 172.16.101.0/24
! !
! !

View File

@ -1,5 +1,9 @@
hostname r1 hostname r1
int dummy0
ip address 10.0.4.1/24
no shut
!
int dummy1 int dummy1
ip address 10.0.0.1/24 ip address 10.0.0.1/24
no shut no shut
@ -16,3 +20,9 @@ int dummy4
ip address 10.0.3.1/24 ip address 10.0.3.1/24
no shut no shut
! !
int EVA
no shut
!
int DONNA
no shut
!

View File

@ -3,6 +3,7 @@
ip link add DONNA type vrf table 1001 ip link add DONNA type vrf table 1001
ip link add EVA type vrf table 1002 ip link add EVA type vrf table 1002
ip link add dummy0 type dummy # vrf default
ip link add dummy1 type dummy ip link add dummy1 type dummy
ip link add dummy2 type dummy ip link add dummy2 type dummy
ip link add dummy3 type dummy ip link add dummy3 type dummy

View File

@ -64,7 +64,7 @@ def teardown_module(mod):
tgen.stop_topology() tgen.stop_topology()
def test_vrf_route_leak(): def test_vrf_route_leak_donna():
logger.info("Ensure that routes are leaked back and forth") logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen() tgen = get_topogen()
# Don't run this test if we have any failure. # Don't run this test if we have any failure.
@ -81,11 +81,59 @@ def test_vrf_route_leak():
} }
], ],
"10.0.1.0/24": [ "10.0.1.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} {
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "EVA",
"vrf": "EVA",
"active": True,
},
],
},
], ],
"10.0.2.0/24": [{"protocol": "connected"}], "10.0.2.0/24": [{"protocol": "connected"}],
"10.0.3.0/24": [ "10.0.3.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} {
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "EVA",
"vrf": "EVA",
"active": True,
},
],
},
],
"10.0.4.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "lo",
"vrf": "default",
"active": True,
},
],
},
],
"172.16.101.0/24": [
{
"protocol": "bgp",
"nexthops": [
{
"interfaceIndex": 0,
"interfaceName": "unknown",
"vrf": "Unknown",
},
],
},
], ],
} }
@ -95,10 +143,31 @@ def test_vrf_route_leak():
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff) assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
def test_vrf_route_leak_eva():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
# Test EVA VRF. # Test EVA VRF.
expect = { expect = {
"10.0.0.0/24": [ "10.0.0.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} {
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
], ],
"10.0.1.0/24": [ "10.0.1.0/24": [
{ {
@ -106,13 +175,36 @@ def test_vrf_route_leak():
} }
], ],
"10.0.2.0/24": [ "10.0.2.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} {
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
], ],
"10.0.3.0/24": [ "10.0.3.0/24": [
{ {
"protocol": "connected", "protocol": "connected",
} }
], ],
"172.16.101.0/24": [
{
"protocol": "bgp",
"nexthops": [
{
"interfaceIndex": 0,
"interfaceName": "unknown",
"vrf": "Unknown",
},
],
},
],
} }
test_func = partial( test_func = partial(
@ -122,6 +214,217 @@ def test_vrf_route_leak():
assert result, "BGP VRF EVA check failed:\n{}".format(diff) assert result, "BGP VRF EVA check failed:\n{}".format(diff)
def test_vrf_route_leak_donna():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
# Test DONNA VRF.
expect = {
"10.0.0.0/24": [
{
"protocol": "connected",
}
],
"10.0.1.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "EVA",
"vrf": "EVA",
"active": True,
},
],
},
],
"10.0.2.0/24": [{"protocol": "connected"}],
"10.0.3.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "EVA",
"vrf": "EVA",
"active": True,
},
],
},
],
"10.0.4.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "lo",
"vrf": "default",
"active": True,
},
],
},
],
"172.16.101.0/24": [
{
"protocol": "bgp",
"nexthops": [
{
"interfaceIndex": 0,
"interfaceName": "unknown",
"vrf": "Unknown",
},
],
},
],
}
test_func = partial(
topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
)
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
def test_vrf_route_leak_eva():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
# Test EVA VRF.
expect = {
"10.0.0.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
],
"10.0.1.0/24": [
{
"protocol": "connected",
}
],
"10.0.2.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
],
"10.0.3.0/24": [
{
"protocol": "connected",
}
],
"172.16.101.0/24": [
{
"protocol": "bgp",
"nexthops": [
{
"interfaceIndex": 0,
"interfaceName": "unknown",
"vrf": "Unknown",
},
],
},
],
}
def test_vrf_route_leak_default():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
# Test default VRF.
expect = {
"10.0.0.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
],
"10.0.2.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
"interfaceName": "DONNA",
"vrf": "DONNA",
"active": True,
},
],
},
],
"10.0.4.0/24": [
{
"protocol": "connected",
}
],
}
test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert result, "BGP VRF default check failed:\n{}".format(diff)
def test_ping():
"Simple ping tests"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
logger.info("Ping from default to DONNA")
output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1")
assert " 0% packet loss" in output, "Ping default->DONNA FAILED"
def test_memory_leak(): def test_memory_leak():
"Run the memory leak test and report results." "Run the memory leak test and report results."
tgen = get_topogen() tgen = get_topogen()

View File

@ -7,5 +7,5 @@ O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX
L>* 10.0.20.1/32 is directly connected, r1-eth1, XX:XX:XX L>* 10.0.20.1/32 is directly connected, r1-eth1, XX:XX:XX
B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX
O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX

View File

@ -9,4 +9,4 @@ O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX
L>* 10.0.20.2/32 is directly connected, r2-eth1, XX:XX:XX L>* 10.0.20.2/32 is directly connected, r2-eth1, XX:XX:XX
O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX

View File

@ -1,9 +1,9 @@
VRF ray: VRF ray:
B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX B 10.0.2.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX
B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX B 10.0.20.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX
C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX