Merge pull request #17491 from pguibert6WIND/bgp_evpn_rt5_routemap

Bgp evpn rt5 routemap
This commit is contained in:
Donatas Abraitis 2024-11-28 16:59:57 +02:00 committed by GitHub
commit 8c9cd28aaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 653 additions and 67 deletions

View file

@ -0,0 +1,131 @@
{
"bgpLocalRouterId":"192.168.100.21",
"defaultLocPrf":100,
"localAS":65000,
"192.168.101.41:2":{
"rd":"192.168.101.41:2",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.101.41",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::2]":{
"prefix":"[5]:[0]:[128]:[fd00::2]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::2",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"192.168.102.21:2":{
"rd":"192.168.102.21:2",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.102.21",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::1]":{
"prefix":"[5]:[0]:[128]:[fd00::1]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::1",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"numPrefix":4,
"totalPrefix":4
}

View file

@ -0,0 +1,191 @@
{
"bgpLocalRouterId":"192.168.100.21",
"defaultLocPrf":100,
"localAS":65000,
"192.168.101.41:2":{
"rd":"192.168.101.41:2",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.101.41",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[32]:[192.168.102.41]":{
"prefix":"[5]:[0]:[32]:[192.168.102.41]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.102.41",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::2]":{
"prefix":"[5]:[0]:[128]:[fd00::2]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::2",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::3]":{
"prefix":"[5]:[0]:[128]:[fd00::3]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::3",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.41",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"192.168.102.21:2":{
"rd":"192.168.102.21:2",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.102.21",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::1]":{
"prefix":"[5]:[0]:[128]:[fd00::1]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::1",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"numPrefix":6,
"totalPrefix":6
}

View file

@ -0,0 +1,131 @@
{
"bgpLocalRouterId":"192.168.100.41",
"defaultLocPrf":100,
"localAS":65000,
"192.168.101.41:2":{
"rd":"192.168.101.41:2",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.101.41",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::2]":{
"prefix":"[5]:[0]:[128]:[fd00::2]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::2",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.41",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"192.168.102.21:2":{
"rd":"192.168.102.21:2",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":32,
"ip":"192.168.102.21",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.21",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
},
"[5]:[0]:[128]:[fd00::1]":{
"prefix":"[5]:[0]:[128]:[fd00::1]",
"prefixLen":352,
"paths":[
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"internal",
"routeType":5,
"ethTag":0,
"ipLen":128,
"ip":"fd00::1",
"metric":0,
"locPrf":100,
"weight":0,
"peerId":"192.168.100.21",
"path":"",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.100.21",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
}
},
"numPrefix":4,
"totalPrefix":4
}

View file

@ -20,12 +20,30 @@ router bgp 65000 vrf r2-vrf-101
no bgp network import-check no bgp network import-check
address-family ipv4 unicast address-family ipv4 unicast
network 192.168.101.41/32 network 192.168.101.41/32
network 192.168.102.41/32
exit-address-family exit-address-family
address-family ipv6 unicast address-family ipv6 unicast
network fd00::2/128 network fd00::2/128
network fd00::3/128
exit-address-family exit-address-family
address-family l2vpn evpn address-family l2vpn evpn
advertise ipv4 unicast advertise ipv4 unicast route-map rmap4
advertise ipv6 unicast advertise ipv6 unicast route-map rmap6
exit-address-family exit-address-family
! !
access-list acl4_1 seq 10 permit 192.168.101.41/32
access-list acl4_2 seq 10 permit 192.168.102.41/32
ipv6 access-list acl6_1 seq 10 permit fd00::2/128
ipv6 access-list acl6_2 seq 10 permit fd00::3/128
route-map rmap4 permit 1
match ip address acl4_1
exit
route-map rmap4 deny 2
match ip address acl4_2
exit
route-map rmap6 permit 1
match ipv6 address acl6_1
exit
route-map rmap6 deny 2
match ipv6 address acl6_2
exit

View file

@ -13,6 +13,8 @@
with route advertisements on a separate netns. with route advertisements on a separate netns.
""" """
import json
from functools import partial
import os import os
import sys import sys
import pytest import pytest
@ -160,6 +162,36 @@ def teardown_module(_mod):
tgen.stop_topology() tgen.stop_topology()
def _test_evpn_ping_router(pingrouter, ipv4_only=False):
"""
internal function to check ping between r1 and r2
"""
# Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn)
logger.info(
"Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)"
)
output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
assertmsg = (
"expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok"
)
assert 0, assertmsg
else:
logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK")
if ipv4_only:
return
logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)")
output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok"
else:
logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK")
def test_protocols_convergence(): def test_protocols_convergence():
""" """
Assert that all protocols have converged Assert that all protocols have converged
@ -168,7 +200,34 @@ def test_protocols_convergence():
tgen = get_topogen() tgen = get_topogen()
if tgen.routers_have_failure(): if tgen.routers_have_failure():
pytest.skip(tgen.errors) pytest.skip(tgen.errors)
topotest.sleep(4, "waiting 4 seconds for bgp convergence") # Check BGP IPv4 routing tables on r1
logger.info("Checking BGP L2VPN EVPN routes for convergence on r1")
for rname in ("r1", "r2"):
router = tgen.gears[rname]
json_file = "{}/{}/bgp_l2vpn_evpn_routes.json".format(CWD, router.name)
if not os.path.isfile(json_file):
assert 0, "bgp_l2vpn_evpn_routes.json file not found"
expected = json.loads(open(json_file).read())
test_func = partial(
topotest.router_json_cmp,
router,
"show bgp l2vpn evpn json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
def test_protocols_dump_info():
"""
Dump EVPN information
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Check IPv4/IPv6 routing tables. # Check IPv4/IPv6 routing tables.
output = tgen.gears["r1"].vtysh_cmd("show bgp l2vpn evpn", isjson=False) output = tgen.gears["r1"].vtysh_cmd("show bgp l2vpn evpn", isjson=False)
logger.info("==== result from show bgp l2vpn evpn") logger.info("==== result from show bgp l2vpn evpn")
@ -203,6 +262,15 @@ def test_protocols_convergence():
logger.info("==== result from show evpn rmac vni all") logger.info("==== result from show evpn rmac vni all")
logger.info(output) logger.info(output)
def test_router_check_ip():
"""
Check routes are correctly installed
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
expected = { expected = {
"fd00::2/128": [ "fd00::2/128": [
{ {
@ -221,56 +289,112 @@ def test_protocols_convergence():
) )
assert result is None, "ipv6 route check failed" assert result is None, "ipv6 route check failed"
expected = {
"101": { def _test_router_check_evpn_contexts(router, ipv4_only=False):
"numNextHops": 2, """
"192.168.100.41": { Check EVPN nexthops and RMAC number are correctly configured
"nexthopIp": "192.168.100.41", """
}, if ipv4_only:
"::ffff:192.168.100.41": { expected = {
"nexthopIp": "::ffff:192.168.100.41", "101": {
}, "numNextHops": 1,
"192.168.100.41": {
"nexthopIp": "192.168.100.41",
},
}
}
else:
expected = {
"101": {
"numNextHops": 2,
"192.168.100.41": {
"nexthopIp": "192.168.100.41",
},
"::ffff:192.168.100.41": {
"nexthopIp": "::ffff:192.168.100.41",
},
}
} }
}
result = topotest.router_json_cmp( result = topotest.router_json_cmp(
tgen.gears["r1"], "show evpn next-hops vni all json", expected router, "show evpn next-hops vni all json", expected
) )
assert result is None, "evpn next-hops check failed" assert result is None, "evpn next-hops check failed"
expected = {"101": {"numRmacs": 1}} expected = {"101": {"numRmacs": 1}}
result = topotest.router_json_cmp( result = topotest.router_json_cmp(router, "show evpn rmac vni all json", expected)
tgen.gears["r1"], "show evpn rmac vni all json", expected
)
assert result is None, "evpn rmac number check failed" assert result is None, "evpn rmac number check failed"
# Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn)
pingrouter = tgen.gears["r1"]
logger.info(
"Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)"
)
output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
assertmsg = (
"expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok"
)
assert 0, assertmsg
else:
logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK")
logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)") def test_router_check_evpn_contexts():
output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000") """
logger.info(output) Check EVPN nexthops and RMAC number are correctly configured
if "1000 packets transmitted, 1000 received" not in output: """
assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok" tgen = get_topogen()
else: if tgen.routers_have_failure():
logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK") pytest.skip(tgen.errors)
_test_router_check_evpn_contexts(tgen.gears["r1"])
def test_evpn_ping():
"""
Check ping between R1 and R2 is ok
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
_test_evpn_ping_router(tgen.gears["r1"])
def test_evpn_disable_routemap():
"""
Check the removal of a route-map on R2. More EVPN Prefixes are expected
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
tgen.gears["r2"].vtysh_cmd(
"""
configure terminal\n
router bgp 65000 vrf r2-vrf-101\n
address-family l2vpn evpn\n
advertise ipv4 unicast\n
advertise ipv6 unicast\n
"""
)
router = tgen.gears["r1"]
json_file = "{}/{}/bgp_l2vpn_evpn_routes_all.json".format(CWD, router.name)
if not os.path.isfile(json_file):
assert 0, "bgp_l2vpn_evpn_routes.json file not found"
expected = json.loads(open(json_file).read())
test_func = partial(
topotest.router_json_cmp,
router,
"show bgp l2vpn evpn json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
def test_evpn_remove_ip():
"""
Check the removal of an EVPN route is correctly handled
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
config_no_ipv6 = { config_no_ipv6 = {
"r2": { "r2": {
"raw_config": [ "raw_config": [
"router bgp 65000 vrf r2-vrf-101", "router bgp 65000 vrf r2-vrf-101",
"address-family ipv6 unicast", "address-family ipv6 unicast",
"no network fd00::3/128",
"no network fd00::2/128", "no network fd00::2/128",
] ]
} }
@ -293,6 +417,7 @@ def test_protocols_convergence():
} }
result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False) result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False)
assert result is not True, "expect IPv6 route fd00::2/128 withdrawn" assert result is not True, "expect IPv6 route fd00::2/128 withdrawn"
output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False) output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False)
logger.info("==== result from show evpn next-hops vni all") logger.info("==== result from show evpn next-hops vni all")
logger.info(output) logger.info(output)
@ -300,37 +425,27 @@ def test_protocols_convergence():
logger.info("==== result from show evpn next-hops vni all") logger.info("==== result from show evpn next-hops vni all")
logger.info(output) logger.info(output)
expected = {
"101": {
"numNextHops": 1,
"192.168.100.41": {
"nexthopIp": "192.168.100.41",
},
}
}
result = topotest.router_json_cmp(
tgen.gears["r1"], "show evpn next-hops vni all json", expected
)
assert result is None, "evpn next-hops check failed"
expected = {"101": {"numRmacs": 1}} def test_router_check_evpn_contexts_again():
result = topotest.router_json_cmp( """
tgen.gears["r1"], "show evpn rmac vni all json", expected Check EVPN nexthops and RMAC number are correctly configured
) """
assert result is None, "evpn rmac number check failed" tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info( _test_router_check_evpn_contexts(tgen.gears["r1"], ipv4_only=True)
"Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)"
)
output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000") def test_evpn_ping_again():
logger.info(output) """
if "1000 packets transmitted, 1000 received" not in output: Check ping between R1 and R2 is ok
assertmsg = ( """
"expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok" tgen = get_topogen()
) if tgen.routers_have_failure():
assert 0, assertmsg pytest.skip(tgen.errors)
else:
logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") _test_evpn_ping_router(tgen.gears["r1"], ipv4_only=True)
def test_memory_leak(): def test_memory_leak():