| d476bb7c | 05-Oct-2026 |
Anton Danilov <littlesmilingcloud@gmail.com> |
vxlan: report a circular route as SKB_DROP_REASON_RECURSION_LIMIT
udp_tunnel_dst_lookup() and udp_tunnel6_dst_lookup() return -ELOOP when the route to the remote end goes out of the vxlan device its
vxlan: report a circular route as SKB_DROP_REASON_RECURSION_LIMIT
udp_tunnel_dst_lookup() and udp_tunnel6_dst_lookup() return -ELOOP when the route to the remote end goes out of the vxlan device itself, and vxlan_xmit_one() counts that in collisions, apart from the -ENETUNREACH of a failed lookup. The drop reason does not tell them apart: both are reported as SKB_DROP_REASON_IP_OUTNOROUTES, which describes a failed route lookup.
Such a route would send the encapsulated packet back into the device it leaves, which is the dead loop on a virtual device that SKB_DROP_REASON_RECURSION_LIMIT describes. Report the -ELOOP case with that reason, and add the tunnel case to the description of the reason as an example. ip_tunnel and ip6_tunnel make the same check, rt->dst.dev == dev in ip_tunnel_xmit() and ip_md_tunnel_xmit() and tdev == dev in ip6_tnl_xmit(), and can report it with the same reason.
Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261005201417.906344-5-littlesmilingcloud@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 0518c33e | 05-Oct-2026 |
Anton Danilov <littlesmilingcloud@gmail.com> |
vxlan: report the drop reason of __iptunnel_pull_header()
vxlan_rcv() reports SKB_DROP_REASON_NOMEM whenever __iptunnel_pull_header() fails, as the helper used to return -ENOMEM for any failure. The
vxlan: report the drop reason of __iptunnel_pull_header()
vxlan_rcv() reports SKB_DROP_REASON_NOMEM whenever __iptunnel_pull_header() fails, as the helper used to return -ENOMEM for any failure. The VXLAN header is already in the linear area at this point, but the inner Ethernet header of a packet without GPE may not be, so a packet whose inner frame is shorter than an Ethernet header is reported as an out of memory condition.
Report the reason __iptunnel_pull_header() now returns instead: PKT_TOO_SMALL for such a packet, NOMEM when an allocation fails.
Suggested-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20261005201417.906344-4-littlesmilingcloud@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 4b74deb1 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: no longer rely on RTNL in vxlan_fill_info()
Now that vxlan->cfg is RCU-protected, we can update vxlan_fill_info() to run under RCU read lock instead of relying on RTNL.
This completes the tr
vxlan: no longer rely on RTNL in vxlan_fill_info()
Now that vxlan->cfg is RCU-protected, we can update vxlan_fill_info() to run under RCU read lock instead of relying on RTNL.
This completes the transition to RTNL-less link info dumping for VXLAN.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-9-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 7e9e6844 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: remove default_dst and use vxlan_config and lowerdev
Now that vxlan->cfg is an RCU-protected pointer, storing default destination attributes (remote_ip, remote_vni, remote_ifindex) in vxlan->
vxlan: remove default_dst and use vxlan_config and lowerdev
Now that vxlan->cfg is an RCU-protected pointer, storing default destination attributes (remote_ip, remote_vni, remote_ifindex) in vxlan->default_dst is redundant and creates potential data races for lockless readers.
Furthermore, several fields of struct vxlan_rdst (remote_port, offloaded, list, rcu, dst_cache) in default_dst were completely unused. The remaining one, remote_dev, only tracked the lower device, a role now taken by vxlan->lowerdev, so drop it from struct vxlan_rdst.
Replace vxlan->default_dst with a 'struct net_device *lowerdev' pointer in struct vxlan_dev to track adjacent upper/lower netdev topology under RTNL, and switch all remaining users over to reading configuration attributes from vxlan->cfg.
Also update mlx5e_tc_tun_get_remote_ifindex() to read remote_ifindex from vxlan->cfg under rcu_read_lock().
In vxlan_changelink(), pass lowerdev to vxlan_config_apply() to preserve needed_headroom and needed_tailroom. The mtu is still only reconsidered when the lower device changes, so that an unrelated changelink can not shrink it.
cfg->remote_ifindex is now committed unconditionally, where default_dst.remote_ifindex was left untouched when IFLA_VXLAN_LINK was cleared, so a changelink dropping the lower device no longer leaves a stale ifindex behind. For the same reason vxlan_changelink() no longer needs to compute the ifindex that will actually be committed.
Setting IFLA_VXLAN_LINK to 0 now also tears down the upper/lower adjacency, which netdev_adjacent_change_commit() used to skip for a NULL new device, resets needed_tailroom, and is rejected if per-VNI multicast groups are configured.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-8-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 0db0197e | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: convert configuration to RCU protection
Move 'struct vxlan_config' from an embedded structure inside 'struct vxlan_dev' to a dynamically allocated RCU-protected pointer 'vxlan->cfg'.
Updatin
vxlan: convert configuration to RCU protection
Move 'struct vxlan_config' from an embedded structure inside 'struct vxlan_dev' to a dynamically allocated RCU-protected pointer 'vxlan->cfg'.
Updating configuration via vxlan_changelink() or vxlan_dev_configure() allocates a new struct vxlan_config and publishes it with rcu_assign_pointer(), freeing the previous config with kfree_rcu().
Readers are converted to use rcu_dereference() or rtnl_dereference(). In vxlan_xmit(), acquire rcu_read_lock() to protect config access.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-7-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 0259a5f1 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: move VXLAN_F_MDB to struct vxlan_dev flags
VXLAN_F_MDB is an internal runtime state flag indicating whether any MDB entries are configured on the device, rather than a netlink configuration a
vxlan: move VXLAN_F_MDB to struct vxlan_dev flags
VXLAN_F_MDB is an internal runtime state flag indicating whether any MDB entries are configured on the device, rather than a netlink configuration attribute.
In preparation for converting vxlan->cfg to an RCU-protected pointer, move VXLAN_F_MDB from struct vxlan_config to a dedicated 'flags' field in struct vxlan_dev as VXLAN_DEV_F_MDB, using atomic bitops (set_bit(), clear_bit(), test_bit()) to avoid KCSAN data races between the TX path and RTNL operations.
This avoids having to dynamically reallocate and publish a new vxlan_config structure via RCU whenever the first MDB entry is added or the last one is removed, and prevents potential memory allocation failures during MDB teardown under memory pressure.
mlxsw validates cfg->flags against a deny-by-default mask, so VXLAN_F_MDB used to make mlxsw_sp_nve_vxlan_can_offload() reject a device with MDB entries as carrying an unsupported flag. Add an explicit VXLAN_DEV_F_MDB test there to keep that rejection, with a message naming the actual reason.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-6-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 3ea46329 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: pass vxlan_config pointer to helper functions
In preparation for converting vxlan->cfg to an RCU-protected pointer, refactor internal helper functions in the RX, TX, MDB, and VNIFILTER paths
vxlan: pass vxlan_config pointer to helper functions
In preparation for converting vxlan->cfg to an RCU-protected pointer, refactor internal helper functions in the RX, TX, MDB, and VNIFILTER paths to accept a pointer to struct vxlan_config (or pass flags/ saddr_family where appropriate) rather than directly accessing vxlan->cfg.
No functional changes.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-5-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| 0e758895 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: vnifilter: signal interrupted RTM_GETTUNNEL dumps
vxlan_vnifilter_dump() walks all vxlan devices of a netns, and for each one walks vg->vni_list. Both cursors are plain ordinals stored in cb-
vxlan: vnifilter: signal interrupted RTM_GETTUNNEL dumps
vxlan_vnifilter_dump() walks all vxlan devices of a netns, and for each one walks vg->vni_list. Both cursors are plain ordinals stored in cb->args[0] and cb->args[1], and RTNL is released between dump skbs.
A concurrent __vxlan_vni_add_list(), which inserts sorted by VNI, __vxlan_vni_del_list(), or an in-place group update in vxlan_vni_update() (which splits or merges coalesced VNI ranges) shifts the second cursor, duplicating or skipping entries. Unregistering a vxlan device shifts the first one, and the partially dumped device is then skipped altogether by the "if (idx < s_idx)" test, silently losing the rest of its VNIs.
Add a per-netns generation counter, bumped whenever the set of vxlan devices in the netns or any vni_list changes, and feed it to nl_dump_check_consistent() so that user space gets NLM_F_DUMP_INTR and can retry, as vxlan_mdb_dump() already does.
The counter is keyed on dev_net(vxlan->dev) rather than vxlan->net, because the dump enumerates devices with for_each_netdev_rcu() in the netns the netdevice lives in, which differs from the packet i/o netns when the device was created with a separate link netns.
Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260922181102.3989489-4-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| d10b7b93 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: vnifilter: use list_for_each_entry_rcu() in vxlan_vnifilter_dump_dev()
RTM_GETTUNNEL dumps currently run under RTNL lock, but vxlan_vnifilter_dump() also acquires rcu_read_lock().
1) Current
vxlan: vnifilter: use list_for_each_entry_rcu() in vxlan_vnifilter_dump_dev()
RTM_GETTUNNEL dumps currently run under RTNL lock, but vxlan_vnifilter_dump() also acquires rcu_read_lock().
1) Currently vxlan_vnifilter_dump_dev() traverses vg->vni_list using list_for_each_entry_safe(). Even though RTNL is held today, writers modify vg->vni_list with list_add_rcu() and list_del_rcu(). Switch to list_for_each_entry_rcu() for proper RCU traversal and as preparation for future lockless dump support.
2) During a paginated dump, RTNL is released between dump skbs. If vxlan_vnifilter_dump_dev() returns early because VXLAN_F_VNIFILTER is not set or vg has no VNIs, cb->args[1] was not cleared. This leaked a non-zero VNI offset to subsequent devices, silently skipping their first N VNIs. Furthermore, if devices are added or removed between dump calls, ordinal device indexes can shift. Track the current device ifindex in cb->args[2] and reset cb->args[1] if the device changes.
Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260922181102.3989489-3-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| b0e75977 | 22-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: update default fdb entries when the lower device changes
vxlan_changelink() only refreshed the default fdb entries when the remote IP changed, but vxlan_config_apply() also updates default_ds
vxlan: update default fdb entries when the lower device changes
vxlan_changelink() only refreshed the default fdb entries when the remote IP changed, but vxlan_config_apply() also updates default_dst.remote_ifindex when the lower device changes. A changelink that only swaps the lower device therefore left the all zeros mac rdst pointing at the old ifindex:
ip link add vxlan0 type vxlan id 10 group 239.1.1.1 dev eth0 ip link set dev vxlan0 type vxlan group 239.1.1.1 dev eth1
vxlan_xmit_one() uses rdst->remote_ifindex as the route oif, so traffic kept leaving eth0.
VNI filter entries have the same problem, and are worse: their fdb entries are keyed on the device remote_ifindex even when the vni carries its own group, but vxlan_vnilist_update_group() only visited the vnis without one. vxlan_vni_delete_group() later looks an entry up with the current remote_ifindex, and vxlan_fdb_find_rdst() requires an exact match, so the lookup failed and the entry survived the delete. Re-adding the same vni then appended a second rdst, duplicating transmitted BUM traffic.
Likewise, in vxlan_vni_update_group(), oldrip was only set when newrip was NULL, so changing an existing VNI's group appended the new rdst without deleting the old one. Set oldrip to the previous effective remote IP whenever updating an existing VNI (!create).
Pass the old and new ifindex down to vxlan_update_default_fdb_entry() so the append targets the new lower device and the delete still matches the entry created for the old one, and refresh every vni rather than only those inheriting the device group. If updating the vni list fails partway through, unwind the already updated fdb entries (still deleting the new rdst even if re-adding the old one fails) so default_dst and the fdb entries do not diverge.
Also run vxlan_multicast_leave() and vxlan_multicast_join() when VXLAN_F_VNIFILTER is set so per-VNI multicast memberships are migrated even when the device default remote_ip is not multicast, and make vxlan_multicast_leave_vnigrp() skip the default group and ignore -EADDRNOTAVAIL when multiple VNIs share a multicast group.
The new ifindex is the one vxlan_config_apply() will commit, which is the current one when lowerdev is NULL, so that default_dst and the fdb entries can not diverge.
Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260922181102.3989489-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| be83178b | 06-Sep-2026 |
Eric Dumazet <edumazet@google.com> |
vxlan: initialize _md in vxlan_xmit_one()
If a VXLAN device is configured with both VXLAN_F_COLLECT_METADATA and VXLAN_F_GBP, and a packet is transmitted through it using an external ip_tunnel_info
vxlan: initialize _md in vxlan_xmit_one()
If a VXLAN device is configured with both VXLAN_F_COLLECT_METADATA and VXLAN_F_GBP, and a packet is transmitted through it using an external ip_tunnel_info that lacks the IP_TUNNEL_VXLAN_OPT_BIT flag, md is left pointing to the uninitialized _md stack variable:
if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT, info->key.tun_flags)) { if (info->options_len < sizeof(*md)) goto drop; md = ip_tunnel_info_opts(info); }
Because IP_TUNNEL_VXLAN_OPT_BIT is not set, md is not updated and remains pointing to _md. Later, vxlan_build_skb() is called with md, which eventually calls vxlan_build_gbp_hdr():
if (vxflags & VXLAN_F_GBP) vxlan_build_gbp_hdr(vxh, md);
Inside vxlan_build_gbp_hdr(), md->gbp is read:
if (!md->gbp) return; gbp = (struct vxlanhdr_gbp *)vxh; ... if (md->gbp & VXLAN_GBP_DONT_LEARN) gbp->dont_learn = 1;
If the stack contains garbage, this causes: 1) VXLAN_HF_GBP flag to be spuriously set in the VXLAN header. 2) gbp->dont_learn and gbp->policy_applied to be set from stack bits. 3) gbp->policy_id to receive 16 bits of uninitialized kernel stack data, leaking it onto the wire.
Fix this by zero-initializing _md. If IP_TUNNEL_VXLAN_OPT_BIT is not present, md->gbp remains 0, and vxlan_build_gbp_hdr() returns early without modifying the VXLAN header.
Fixes: ee122c79d422 ("vxlan: Flow based tunneling") Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260906180111.1973188-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
show more ...
|
| bc2dc66a | 14-Aug-2026 |
Baul Lee <baul.lee@xbow.com> |
vxlan: mdb: Fix use-after-free in vxlan_mdb_flush()
vxlan_mdb_flush() iterates over the MDB entries using hlist_for_each_entry_safe(), which only tolerates the removal of the current entry. Contrary
vxlan: mdb: Fix use-after-free in vxlan_mdb_flush()
vxlan_mdb_flush() iterates over the MDB entries using hlist_for_each_entry_safe(), which only tolerates the removal of the current entry. Contrary to the comment above the loop, the removal of an entry can trigger the removal of another entry.
Flushing the remotes of a (*, G) entry also removes the (S, G) entries that were created for its source list, once they are left without remotes:
vxlan_mdb_remotes_flush() -> vxlan_mdb_remote_del() -> vxlan_mdb_remote_srcs_del() -> vxlan_mdb_remote_src_del() -> vxlan_mdb_remote_src_fwd_del() -> __vxlan_mdb_del() -> vxlan_mdb_entry_put()
Such an entry can be located after the (*, G) entry in the list, as vxlan_mdb_entry_get() returns an existing entry without moving it to the head of the list. This order is obtained by adding the (S, G) entry before the (*, G) entry, the latter with NLM_F_REPLACE, as the addition of the source otherwise fails with -EEXIST. The (S, G) entry is then the entry saved by hlist_for_each_entry_safe() and it is freed while the (*, G) entry is processed. The next iteration calls hlist_del() on it again, writing LIST_POISON1 to LIST_POISON2 [1].
Besides device deletion, the flush is also reachable from RTM_DELMDB with NLM_F_BULK.
Fix by re-reading the next entry after the remotes were flushed. The current entry cannot be removed by this flush, as source lists can only be configured on (*, G) entries and the removed entries are (S, G) entries. It is therefore still linked and its next pointer reflects the removals.
[1] BUG: KASAN: wild-memory-access in vxlan_mdb_entry_put.part.0+0x328/0x588 Write of size 8 at addr dead000000000122 by task ip/327
CPU: 3 UID: 1000 PID: 327 Comm: ip Not tainted 7.2.0-rc7 #2 PREEMPT Call trace: vxlan_mdb_entry_put.part.0+0x328/0x588 vxlan_mdb_flush+0x1d8/0x25c vxlan_mdb_fini+0x8c/0x100 vxlan_uninit+0x1c/0x7c unregister_netdevice_many_notify+0x954/0xd4c rtnl_dellink+0x210/0x530 rtnetlink_rcv_msg+0x434/0x4d0 netlink_rcv_skb+0xc4/0x204 rtnetlink_rcv+0x18/0x24 netlink_unicast+0x4b8/0x548 netlink_sendmsg+0x29c/0x560 ____sys_sendmsg+0x390/0x3ec ___sys_sendmsg+0x114/0x188 __sys_sendmsg+0xf0/0x178 __arm64_sys_sendmsg+0x48/0x60 invoke_syscall.constprop.0+0x58/0x180 el0_svc_common.constprop.0+0x74/0x140 do_el0_svc+0x30/0x40 el0_svc+0x38/0x98 el0t_64_sync_handler+0xa0/0xe4 el0t_64_sync+0x198/0x19c
Fixes: a3a48de5eade ("vxlan: mdb: Add MDB control path support") Signed-off-by: Baul Lee <baul.lee@xbow.com> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Link: https://patch.msgid.link/20260814153547.29567-1-baul.lee@xbow.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
show more ...
|