Merge pull request #17580 from varuntumbe/dev/label_pool_release_fix

BGP Labelpool : Releasing the label in labelpool when VPN session gets removed
This commit is contained in:
Donatas Abraitis 2024-12-23 14:48:21 +02:00 committed by GitHub
commit 9ce3b144c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 463 additions and 19 deletions

View file

@ -4079,6 +4079,35 @@ void bgp_vpn_leak_export(struct bgp *from_bgp)
}
}
/* It releases the label from labelpool which
* was previously assigned and unsets the flag based on reset arg
* This also used in vty to release the label and to change the allocation mode as well
*/
void bgp_vpn_release_label(struct bgp *bgp, afi_t afi, bool reset)
{
if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO))
return;
/*
* label has previously been automatically
* assigned by labelpool: release it
*
* NB if tovpn_label == MPLS_LABEL_NONE it
* means the automatic assignment is in flight
* and therefore the labelpool callback must
* detect that the auto label is not needed.
*/
if (bgp->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)
return;
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP))
return;
bgp_lp_release(LP_TYPE_VRF, &bgp->vpn_policy[afi], bgp->vpn_policy[afi].tovpn_label);
bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
if (reset)
UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
}
/* The nexthops values are compared to
* find in the tree the appropriate cache entry
*/

View file

@ -352,6 +352,7 @@ extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
bool is_config);
extern void bgp_vpn_leak_unimport(struct bgp *from_bgp);
extern void bgp_vpn_leak_export(struct bgp *from_bgp);
extern void bgp_vpn_release_label(struct bgp *bgp, afi_t afi, bool reset);
extern bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi);
extern int

View file

@ -9948,26 +9948,9 @@ DEFPY (af_label_vpn_export,
UNSET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG);
} else if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
} else if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO))
/* release any previous auto label */
if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
/*
* label has previously been automatically
* assigned by labelpool: release it
*
* NB if tovpn_label == MPLS_LABEL_NONE it
* means the automatic assignment is in flight
* and therefore the labelpool callback must
* detect that the auto label is not needed.
*/
bgp_lp_release(LP_TYPE_VRF,
&bgp->vpn_policy[afi],
bgp->vpn_policy[afi].tovpn_label);
}
}
bgp_vpn_release_label(bgp, afi, false);
if (yes) {
if (label_auto) {

View file

@ -4037,6 +4037,9 @@ int bgp_delete(struct bgp *bgp)
bgp_vpn_leak_unimport(bgp);
bgp_vpn_release_label(bgp, AFI_IP, true);
bgp_vpn_release_label(bgp, AFI_IP6, true);
hook_call(bgp_inst_delete, bgp);
FOREACH_AFI_SAFI (afi, safi)

View file

@ -0,0 +1,117 @@
interface r1-eth1 vrf vrf1
ip address 173.31.1.1/32
!
interface r1-eth2 vrf vrf2
ip address 173.31.1.2/32
!
interface r1-eth3 vrf vrf3
ip address 173.31.1.3/32
!
interface r1-eth4 vrf vrf4
ip address 173.31.1.4/32
!
interface r1-eth5 vrf vrf5
ip address 173.31.1.5/32
!
interface r1-eth0
ip address 192.168.0.1/24
!
interface r1-eth6
ip address 193.170.0.1/24
interface lo
ip address 11.11.11.11/32
!
router ospf
ospf router-id 11.11.11.11
network 193.170.0.0/24 area 0.0.0.0
network 11.11.11.11/32 area 0.0.0.0
redistribute connected
exit
!
mpls ldp
router-id 11.11.11.11
!
address-family ipv4
discovery transport-address 11.11.11.11
!
interface r1-eth6
exit
!
exit-address-family
!
exit
!
bgp route-map delay-timer 1
router bgp 65500
bgp router-id 192.0.2.1
no bgp ebgp-requires-policy
neighbor 192.168.0.2 remote-as 65501
address-family ipv4 unicast
no neighbor 192.168.0.2 activate
exit-address-family
address-family ipv4 vpn
neighbor 192.168.0.2 activate
exit-address-family
!
router bgp 65500 vrf vrf1
bgp router-id 192.0.2.1
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:1
rt vpn both 53:1
export vpn
import vpn
exit-address-family
!
router bgp 65500 vrf vrf2
bgp router-id 192.0.2.1
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:2
rt vpn both 53:2
export vpn
import vpn
exit-address-family
!
router bgp 65500 vrf vrf3
bgp router-id 192.0.2.1
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:3
rt vpn both 53:3
export vpn
import vpn
exit-address-family
!
router bgp 65500 vrf vrf4
bgp router-id 192.0.2.1
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:4
rt vpn both 53:4
export vpn
import vpn
exit-address-family
!
router bgp 65500 vrf vrf5
bgp router-id 192.0.2.1
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:5
rt vpn both 53:5
export vpn
import vpn
exit-address-family
!
interface r1-eth0
mpls bgp forwarding
!

View file

@ -0,0 +1,88 @@
interface r2-eth1 vrf vrf1
ip address 173.31.0.1/32
!
interface r2-eth2 vrf vrf2
ip address 173.31.0.2/32
!
interface r2-eth3 vrf vrf3
ip address 173.31.0.3/32
!
interface r2-eth4 vrf vrf4
ip address 173.31.0.4/32
!
interface r2-eth5 vrf vrf5
ip address 173.31.0.5/32
!
interface r2-eth0
ip address 192.168.0.2/24
!
router bgp 65501
bgp router-id 192.0.2.2
no bgp ebgp-requires-policy
neighbor 192.168.0.1 remote-as 65500
address-family ipv4 unicast
no neighbor 192.168.0.1 activate
exit-address-family
address-family ipv4 vpn
neighbor 192.168.0.1 activate
exit-address-family
!
router bgp 65501 vrf vrf1
bgp router-id 192.0.2.2
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:1
rt vpn both 53:1
export vpn
import vpn
exit-address-family
!
router bgp 65501 vrf vrf2
bgp router-id 192.0.2.2
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:2
rt vpn both 53:2
export vpn
import vpn
exit-address-family
!
router bgp 65501 vrf vrf3
bgp router-id 192.0.2.2
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:3
rt vpn both 53:3
export vpn
import vpn
exit-address-family
!
router bgp 65501 vrf vrf4
bgp router-id 192.0.2.2
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:4
rt vpn both 53:4
export vpn
import vpn
exit-address-family
!
router bgp 65501 vrf vrf5
bgp router-id 192.0.2.2
address-family ipv4 unicast
redistribute connected
label vpn export auto
rd vpn export 445:5
rt vpn both 53:5
export vpn
import vpn
exit-address-family
!
interface r2-eth0
mpls bgp forwarding
!

View file

@ -0,0 +1,32 @@
interface r3-eth0
ip address 193.170.0.2/24
!
interface lo
ip address 33.33.33.33/32
!
interface r3-eth1
ip address 180.170.0.2/32
!
interface r3-eth2
ip address 180.170.0.3/32
!
router ospf
ospf router-id 33.33.33.33
network 193.170.0.0/24 area 0.0.0.0
network 33.33.33.33/32 area 0.0.0.0
redistribute connected
exit
!
mpls ldp
router-id 33.33.33.33
!
address-family ipv4
discovery transport-address 33.33.33.33
!
interface r3-eth0
exit
!
exit-address-family
!
exit
!

View file

@ -0,0 +1,191 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
#
# test_bgp_vpnv4_vpn_auto.py
#
# Copyright (c) 2024 by Varun Hegde
#
"""
test_bgp_vpnv4_vpn_auto.py: Test the FRR BGP daemon with BGP VPN session with label export auto
"""
import os
import sys
import json
import functools
import pytest
# Save the Current Working Directory to find configuration files.
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.bgpcheck import (
check_show_bgp_vpn_prefix_found,
check_show_bgp_vpn_prefix_not_found,
)
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
# Required to instantiate the topology builder class.
pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
"Build function"
# Create 3 routers.
tgen.add_router("r1")
tgen.add_router("r2")
tgen.add_router("r3")
for i in range(6):
switch = tgen.add_switch("s{0}".format(i))
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
#create a singiluar link between R2 -- R3
switch = tgen.add_switch("s6")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r3"])
for i in range(7, 9):
switch = tgen.add_switch("s{0}".format(i))
switch.add_link(tgen.gears["r3"])
def _populate_iface():
tgen = get_topogen()
cmds_list = [
"ip link add vrf{} type vrf table {}",
"ip link set dev vrf{} up",
"ip link set dev r1-eth{} master vrf{}",
"echo 1 > /proc/sys/net/mpls/conf/r1-eth{}/input",
]
cmds_list2 = [
"ip link add vrf{} type vrf table {}",
"ip link set dev vrf{} up",
"ip link set dev r2-eth{} master vrf{}",
"echo 1 > /proc/sys/net/mpls/conf/r2-eth{}/input",
]
for i in range(1, 6):
for cmd in cmds_list:
input = cmd.format(i, i)
logger.info("input: " + cmd)
output = tgen.net["r1"].cmd(cmd.format(i, i))
logger.info("output: " + output)
for cmd in cmds_list2:
input = cmd.format(i, i)
logger.info("input: " + cmd)
output = tgen.net["r2"].cmd(cmd.format(i, i))
logger.info("output: " + output)
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
_populate_iface()
for rname, router in router_list.items():
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
# Initialize all routers.
tgen.start_router()
def teardown_module(_mod):
"Teardown the pytest environment"
tgen = get_topogen()
tgen.stop_topology()
def test_labelpool_release():
"""
Check that once we remove BGP VPN sesson
label pool structure ( allocated_map ) gets released properly or not
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Just waiting for BGP VPN session to converge
logger.info("Waiting for BGP VPN sessions to converge and label pools to get initialised")
router = tgen.gears["r1"]
def _bgp_converge():
output = json.loads(
router.vtysh_cmd("show bgp labelpool summary json")
)
expected = {"ledger":5,"inUse":5,"requests":0,"labelChunks":1,"pending":0,"reconnects":1}
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 BGP Labelpool initialised"
# checking the initial label pool chunk's free labels
logger.info("checking the initial label pool chunk's free labels")
expected = [{"first":80,"last":207,"size":128,"numberFree":123}]
test_func = functools.partial(
topotest.router_json_cmp,
router,
"show bgp label chunks json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
# Test case : check whether label got released or not
logger.info(
"Remove multiple vpn session and check whether label got released or no"
)
router.vtysh_cmd(
"""
configure terminal
no router bgp 65500 vrf vrf1
no router bgp 65500 vrf vrf2
"""
)
expected = [{"first":80,"last":207,"size":128,"numberFree":125}]
test_func = functools.partial(
topotest.router_json_cmp,
router,
"show bgp label chunks json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip("Memory leak test/report is disabled")
tgen.report_memory_leaks()
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))