Skip to content

Commit

Permalink
Merge branch 'vxlan-age-fdb-entries-based-on-rx-traffic'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
vxlan: Age FDB entries based on Rx traffic

tl;dr - This patchset prevents VXLAN FDB entries from lingering if
traffic is only forwarded to a silent host.

The VXLAN driver maintains two timestamps for each FDB entry: 'used' and
'updated'. The first is refreshed by both the Rx and Tx paths and the
second is refreshed upon migration.

The driver ages out entries according to their 'used' time which means
that an entry can linger when traffic is only forwarded to a silent host
that might have migrated to a different remote.

This patchset solves the problem by adjusting the above semantics and
aligning them to those of the bridge driver. That is, 'used' time is
refreshed by the Tx path, 'updated' time is refresh by Rx path or user
space updates and entries are aged out according to their 'updated'
time.

Patches #1-#2 perform small changes in how the 'used' and 'updated'
fields are accessed.

Patches #3-#5 refresh the 'updated' time where needed.

Patch #6 flips the driver to age out FDB entries according to their
'updated' time.

Patch #7 removes unnecessary updates to the 'used' time.

Patch #8 extends a test case to cover aging of FDB entries in the
presence of Tx traffic.
====================

Link: https://patch.msgid.link/20250204145549.1216254-1-idosch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Feb 6, 2025
2 parents 50f37fc + c467a98 commit 3924fa9
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 13 deletions.
32 changes: 19 additions & 13 deletions drivers/net/vxlan/vxlan_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,9 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
be32_to_cpu(fdb->vni)))
goto nla_put_failure;

ci.ndm_used = jiffies_to_clock_t(now - fdb->used);
ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used));
ci.ndm_confirmed = 0;
ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated);
ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated));
ci.ndm_refcnt = 0;

if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
Expand Down Expand Up @@ -434,8 +434,12 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
struct vxlan_fdb *f;

f = __vxlan_find_mac(vxlan, mac, vni);
if (f && f->used != jiffies)
f->used = jiffies;
if (f) {
unsigned long now = jiffies;

if (READ_ONCE(f->used) != now)
WRITE_ONCE(f->used, now);
}

return f;
}
Expand Down Expand Up @@ -1009,12 +1013,10 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
!(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
if (f->state != state) {
f->state = state;
f->updated = jiffies;
notify = 1;
}
if (f->flags != fdb_flags) {
f->flags = fdb_flags;
f->updated = jiffies;
notify = 1;
}
}
Expand Down Expand Up @@ -1048,12 +1050,13 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
}

if (ndm_flags & NTF_USE)
f->used = jiffies;
WRITE_ONCE(f->updated, jiffies);

if (notify) {
if (rd == NULL)
rd = first_remote_rtnl(f);

WRITE_ONCE(f->updated, jiffies);
err = vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH,
swdev_notify, extack);
if (err)
Expand Down Expand Up @@ -1292,7 +1295,7 @@ int __vxlan_fdb_delete(struct vxlan_dev *vxlan,
struct vxlan_fdb *f;
int err = -ENOENT;

f = vxlan_find_mac(vxlan, addr, src_vni);
f = __vxlan_find_mac(vxlan, addr, src_vni);
if (!f)
return err;

Expand Down Expand Up @@ -1459,9 +1462,13 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev,
ifindex = src_ifindex;
#endif

f = vxlan_find_mac(vxlan, src_mac, vni);
f = __vxlan_find_mac(vxlan, src_mac, vni);
if (likely(f)) {
struct vxlan_rdst *rdst = first_remote_rcu(f);
unsigned long now = jiffies;

if (READ_ONCE(f->updated) != now)
WRITE_ONCE(f->updated, now);

if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) &&
rdst->remote_ifindex == ifindex))
Expand All @@ -1481,7 +1488,6 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev,
src_mac, &rdst->remote_ip.sa, &src_ip->sa);

rdst->remote_ip = *src_ip;
f->updated = jiffies;
vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL);
} else {
u32 hash_index = fdb_head_index(vxlan, src_mac, vni);
Expand Down Expand Up @@ -2852,7 +2858,7 @@ static void vxlan_cleanup(struct timer_list *t)
if (f->flags & NTF_EXT_LEARNED)
continue;

timeout = f->used + vxlan->cfg.age_interval * HZ;
timeout = READ_ONCE(f->updated) + vxlan->cfg.age_interval * HZ;
if (time_before_eq(timeout, jiffies)) {
netdev_dbg(vxlan->dev,
"garbage collect %pM\n",
Expand Down Expand Up @@ -4765,7 +4771,7 @@ vxlan_fdb_offloaded_set(struct net_device *dev,

spin_lock_bh(&vxlan->hash_lock[hash_index]);

f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
f = __vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
if (!f)
goto out;

Expand Down Expand Up @@ -4821,7 +4827,7 @@ vxlan_fdb_external_learn_del(struct net_device *dev,
hash_index = fdb_head_index(vxlan, fdb_info->eth_addr, fdb_info->vni);
spin_lock_bh(&vxlan->hash_lock[hash_index]);

f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
f = __vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
if (!f)
err = -ENOENT;
else if (f->flags & NTF_EXT_LEARNED)
Expand Down
2 changes: 2 additions & 0 deletions tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,8 @@ test_learning()

vxlan_flood_test $mac $dst 0 10 0

# The entry should age out when it only forwards traffic
$MZ $h1 -c 50 -d 1sec -p 64 -b $mac -B $dst -t icmp -q &
sleep 60

bridge fdb show brport vx1 | grep $mac | grep -q self
Expand Down

0 comments on commit 3924fa9

Please sign in to comment.