[PATCH net v5 2/2] vxlan: reject VNI add when the default fdb entry is nexthop-backed

From: Henry Martin

Date: Wed Oct 28 2026 - 07:17:59 EST


vxlan_vni_add() installs the new VNI - hash table insert, group list,
socket attach and the RTM_NEWTUNNEL notification - before calling
vxlan_vni_update_group(), which in turn calls
vxlan_update_default_fdb_entry() to store the group (or the device's
default remote) into the all-zeros fdb entry of that VNI.

Now that vxlan_fdb_update_existing() rejects appending a remote to a
nexthop-backed default entry, the group store can fail with
-EOPNOTSUPP after the VNI has already been installed and announced,
leaving it half-installed: present in the tables and announced, but
with no remote stored and no multicast join.

Check whether the default fdb entry for the VNI is backed by a
nexthop before installing the VNI, and reject the add up front.

Note: the missing unwind in vxlan_vni_add() predates this series;
this check avoids giving user space a deterministic way to reach it.

Cc: stable@xxxxxxxxxxxxxxx
Fixes: 1274e1cc4226 ("vxlan: ecmp support for mac fdb entries")
Signed-off-by: Henry Martin <bsdhenrymartin@xxxxxxxxx>
---

v5: fix a build error on current net/main: vxlan->cfg became an
RCU-managed pointer, so reference the function-local cfg
(reported by kernel test robot).

v4: new patch; the failure path was made reachable by patch 1, so
guard it before the VNI is installed (sashiko review of v2).

drivers/net/vxlan/vxlan_core.c | 14 ++++++++++++++
drivers/net/vxlan/vxlan_private.h | 2 ++
drivers/net/vxlan/vxlan_vnifilter.c | 14 ++++++++++++++
3 files changed, 30 insertions(+)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 3390e341d1e58..13143085065f6 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -422,6 +422,20 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
return f;
}

+bool vxlan_fdb_entry_nh_backed(struct vxlan_dev *vxlan, const u8 *mac,
+ __be32 vni)
+{
+ struct vxlan_fdb *f;
+ bool ret;
+
+ spin_lock_bh(&vxlan->hash_lock);
+ f = vxlan_find_mac(vxlan, mac, vni);
+ ret = f && rcu_access_pointer(f->nh);
+ spin_unlock_bh(&vxlan->hash_lock);
+
+ return ret;
+}
+
/* caller should hold vxlan->hash_lock */
static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port,

diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h
index b1eec22163608..0454689965aeb 100644
--- a/drivers/net/vxlan/vxlan_private.h
+++ b/drivers/net/vxlan/vxlan_private.h
@@ -11,6 +11,8 @@

extern unsigned int vxlan_net_id;
extern const u8 all_zeros_mac[ETH_ALEN + 2];
+bool vxlan_fdb_entry_nh_backed(struct vxlan_dev *vxlan,
+ const u8 *mac, __be32 vni);
extern const struct rhashtable_params vxlan_vni_rht_params;

#define PORT_HASH_BITS 8

diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index dd94085e08865..f07ae2a6a59ed 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -737,6 +737,20 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan,
return err;
}

+ /* A default fdb entry that is backed by a nexthop group can
+ * never take a remote; reject before the VNI is installed,
+ * otherwise a failure in vxlan_vni_update_group() would leave
+ * the VNI half-installed.
+ */
+ if ((group && !vxlan_addr_any(group)) ||
+ !vxlan_addr_any(&cfg->remote_ip)) {
+ if (vxlan_fdb_entry_nh_backed(vxlan, all_zeros_mac, v)) {
+ NL_SET_ERR_MSG(extack,
+ "Cannot add a remote to a nexthop fdb entry");
+ return -EOPNOTSUPP;
+ }
+ }
+
vninode = vxlan_vni_alloc(vxlan, v);
if (!vninode)
return -ENOMEM;
--
2.43.7