Commit 080f85ae37 for frr
commit 080f85ae37c830c08534001c56d8f7d51e459040
Author: Maxime Gouin <maxime.gouin@6wind.com>
Date: Fri Oct 16 10:48:36 2026 +0200
zebra: free L2-VNI of deleted vxlan interface when EVPN is disabled
When EVPN is disabled, zebra_vxlan_if_del_vni() returns early, so the
L2-VNI entry (struct zebra_evpn) bound to a deleted VxLAN interface is
not freed. Such entries can exist while EVPN is disabled: they are kept
when bgpd disconnects (zebra_evpn_bgp_cfg_clean_up()) and they are
created when a vrf-vni mapping is removed
(zebra_vxlan_handle_vni_transition()).
Since commit 988738a787 ("zebra: Don't leave stale interface pointers
in the VNI databases"), the reference to the deleted VxLAN interface
(zevpn->vxlan_if) is cleared, which avoids a use-after-free when EVPN
is enabled again. However, the L2-VNI entry itself is leaked: it stays
in the EVPN table without a VxLAN interface, and is still shown by
"show evpn vni" once EVPN is enabled again.
Delete the L2-VNI entry bound to the deleted VxLAN interface even if
EVPN is disabled, and only if it is actually bound to this interface.
Only the L3-VNI processing still requires EVPN to be enabled.
Signed-off-by: Maxime Gouin <maxime.gouin@6wind.com>
diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c
index 188aa0284c..8f388434ef 100644
--- a/zebra/zebra_vxlan_if.c
+++ b/zebra/zebra_vxlan_if.c
@@ -145,15 +145,12 @@ static int zebra_vxlan_if_del_vni(struct interface *ifp,
struct zebra_l3vni *zl3vni;
struct interface *br_if;
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
zif = ifp->info;
assert(zif);
vni = vnip->vni;
- zl3vni = zl3vni_lookup(vni);
+ /* L3-VNIs are only processed while EVPN is enabled. */
+ zl3vni = is_evpn_enabled() ? zl3vni_lookup(vni) : NULL;
if (zl3vni) {
if (IS_ZEBRA_DEBUG_VXLAN)
@@ -176,12 +173,17 @@ static int zebra_vxlan_if_del_vni(struct interface *ifp,
zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name,
ifp->ifindex);
- /* Locate hash entry; it is expected to exist. */
+ /*
+ * L2-VNI hash entries survive a BGP disconnect (see
+ * zebra_evpn_bgp_cfg_clean_up()) and are created by vrf-vni
+ * removal, so they must be freed here even when EVPN is
+ * disabled, or they leak.
+ */
zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
+ if (!zevpn || zevpn->vxlan_if != ifp) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("No L2-VNI %u bound to intf %s(%u) at del", vni,
+ ifp->name, ifp->ifindex);
return 0;
}