From 6f3f017121a915e3537026a7040d7f5652bbe21b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 31 Dec 2024 14:38:11 +0100 Subject: [PATCH] bgpd: fix duplicate BGP instance created with unified config When running the bgp_evpn_rt5 setup with unified config, memory leak about a non deleted BGP instance happens. > root@ubuntu2204hwe:~/frr/tests/topotests/bgp_evpn_rt5# cat /tmp/topotests/bgp_evpn_rt5.test_bgp_evpn/r1.asan.bgpd.1164105 > > ================================================================= > ==1164105==ERROR: LeakSanitizer: detected memory leaks > > Indirect leak of 12496 byte(s) in 1 object(s) allocated from: > #0 0x7f358eeb4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x7f358e877233 in qcalloc lib/memory.c:106 > #2 0x55d06c95680a in bgp_create bgpd/bgpd.c:3405 > #3 0x55d06c95a7b3 in bgp_get bgpd/bgpd.c:3805 > #4 0x55d06c87a9b5 in bgp_get_vty bgpd/bgp_vty.c:603 > #5 0x55d06c68dc71 in bgp_evpn_local_l3vni_add bgpd/bgp_evpn.c:7032 > #6 0x55d06c92989b in bgp_zebra_process_local_l3vni bgpd/bgp_zebra.c:3204 > #7 0x7f358e9e3feb in zclient_read lib/zclient.c:4626 > #8 0x7f358e98082d in event_call lib/event.c:1996 > #9 0x7f358e848931 in frr_run lib/libfrr.c:1232 > #10 0x55d06c60eae1 in main bgpd/bgp_main.c:557 > #11 0x7f358e229d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 Actually, a BGP VRF Instance is created in auto mode when creating the global BGP instance for the L3 VNI. And again, an other BGP VRF instance is created. Fix this by ensuring that a non existing BGP instance is not present. If it is present, and with auto mode or in hidden mode, then override the AS value. Fixes: f153b9a9b636 ("bgpd: Ignore auto created VRF BGP instances") Signed-off-by: Philippe Guibert fixup bgpd: fix duplicate BGP instance created with unified config --- bgpd/bgp_vty.c | 18 ++++++++++-------- bgpd/bgpd.c | 29 ++++++++++++++++++++--------- bgpd/bgpd.h | 9 ++++----- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 550adf93dba1..19cce5d71dd2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1509,13 +1509,12 @@ DEFUN_NOSH (router_bgp, int idx_asn = 2; int idx_view_vrf = 3; int idx_vrf = 4; - int is_new_bgp = 0; int idx_asnotation = 3; int idx_asnotation_kind = 4; enum asnotation_mode asnotation = ASNOTATION_UNDEFINED; int ret; as_t as; - struct bgp *bgp; + struct bgp *bgp = NULL; const char *name = NULL; enum bgp_instance_type inst_type; @@ -1577,11 +1576,14 @@ DEFUN_NOSH (router_bgp, asnotation = ASNOTATION_PLAIN; } - if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) - is_new_bgp = (bgp_lookup(as, name) == NULL); - - ret = bgp_get_vty(&bgp, &as, name, inst_type, - argv[idx_asn]->arg, asnotation); + ret = bgp_lookup_by_as_name_type(&bgp, &as, argv[idx_asn]->arg, asnotation, name, + inst_type, true); + if (bgp && ret == BGP_INSTANCE_EXISTS) + ret = CMD_SUCCESS; + else if (bgp == NULL && ret == CMD_SUCCESS) + /* SUCCESS and bgp is NULL */ + ret = bgp_get_vty(&bgp, &as, name, inst_type, argv[idx_asn]->arg, + asnotation); switch (ret) { case BGP_ERR_AS_MISMATCH: vty_out(vty, "BGP is already running; AS is %s\n", @@ -1601,7 +1603,7 @@ DEFUN_NOSH (router_bgp, * any pending VRF-VPN leaking that was configured via * earlier "router bgp X vrf FOO" blocks. */ - if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT) + if (bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT) vpn_leak_postchange_all(); if (inst_type == BGP_INSTANCE_TYPE_VRF || diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2f234e3a5a4f..30ba393435ce 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3630,13 +3630,13 @@ struct bgp *bgp_lookup(as_t as, const char *name) } /* Lookup BGP structure by view name. */ -struct bgp *bgp_lookup_by_name(const char *name) +static struct bgp *_bgp_lookup_by_name(const char *name, bool all) { struct bgp *bgp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + if (all == false && CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) continue; if ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp(bgp->name, name) == 0)) @@ -3645,6 +3645,16 @@ struct bgp *bgp_lookup_by_name(const char *name) return NULL; } +struct bgp *bgp_lookup_by_name(const char *name) +{ + return _bgp_lookup_by_name(name, false); +} + +struct bgp *bgp_lookup_by_name_all(const char *name) +{ + return _bgp_lookup_by_name(name, true); +} + /* Lookup BGP instance based on VRF id. */ /* Note: Only to be used for incoming messages from Zebra. */ struct bgp *bgp_lookup_by_vrf_id(vrf_id_t vrf_id) @@ -3730,10 +3740,9 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id, return bgp_check_main_socket(create, bgp); } -int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, - const char *as_pretty, +int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *as_pretty, enum asnotation_mode asnotation, const char *name, - enum bgp_instance_type inst_type) + enum bgp_instance_type inst_type, bool force_config) { struct bgp *bgp; struct peer *peer = NULL; @@ -3741,7 +3750,9 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, bool hidden = false; /* Multiple instance check. */ - if (name) + if (name && force_config) + bgp = bgp_lookup_by_name_all(name); + else if (name) bgp = bgp_lookup_by_name(name); else bgp = bgp_get_default(); @@ -3752,7 +3763,7 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, /* Handle AS number change */ if (bgp->as != *as) { if (hidden || CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) { - if (hidden) { + if (force_config == false && hidden) { bgp_create(as, name, inst_type, as_pretty, asnotation, bgp, hidden); @@ -3761,6 +3772,7 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, } else { bgp->as = *as; UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO); + UNSET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN); } /* Set all peer's local AS with this ASN */ @@ -3797,8 +3809,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, struct vrf *vrf = NULL; int ret = 0; - ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation, - name, inst_type); + ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation, name, inst_type, false); if (ret || *bgp_val) return ret; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 47214e52e5fa..fbdcf89404f2 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2281,6 +2281,7 @@ extern void bgp_zclient_reset(void); extern struct bgp *bgp_get_default(void); extern struct bgp *bgp_lookup(as_t, const char *); extern struct bgp *bgp_lookup_by_name(const char *); +extern struct bgp *bgp_lookup_by_name_all(const char *name); extern struct bgp *bgp_lookup_by_vrf_id(vrf_id_t); extern struct bgp *bgp_get_evpn(void); extern void bgp_set_evpn(struct bgp *bgp); @@ -2855,11 +2856,9 @@ extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, const char *ip_str, bool use_json); -extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, - const char *as_pretty, - enum asnotation_mode asnotation, - const char *name, - enum bgp_instance_type inst_type); +extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *as_pretty, + enum asnotation_mode asnotation, const char *name, + enum bgp_instance_type inst_type, bool force_config); /* Hooks */ DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),