wifi: mac80211: split mesh fast tx cache into local/proxied/forwarded
authorFelix Fietkau <nbd@nbd.name>
Mon, 15 Apr 2024 12:18:11 +0000 (14:18 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 17 Apr 2024 07:21:32 +0000 (09:21 +0200)
Depending on the origin of the packets (and their SA), 802.11 + mesh headers
could be filled in differently. In order to properly deal with that, add a
new field to the lookup key, indicating the type (local, proxied or
forwarded). This can fix spurious packet drop issues that depend on the order
in which nodes/hosts communicate with each other.

Fixes: d5edb9ae8d56 ("wifi: mac80211: mesh fast xmit support")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Link: https://msgid.link/20240415121811.13391-1-nbd@nbd.name
[use sizeof_field() for key_len]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_pathtbl.c
net/mac80211/rx.c

index 32475da98d739cbe66d200f6bd8e8b0542f3cb04..cbc9b5e40cb35e81fb80dd55016c3afc8c31deb7 100644 (file)
@@ -747,6 +747,9 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
                              struct sk_buff *skb, u32 ctrl_flags)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       struct ieee80211_mesh_fast_tx_key key = {
+               .type = MESH_FAST_TX_TYPE_LOCAL
+       };
        struct ieee80211_mesh_fast_tx *entry;
        struct ieee80211s_hdr *meshhdr;
        u8 sa[ETH_ALEN] __aligned(2);
@@ -782,7 +785,10 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
                        return false;
        }
 
-       entry = mesh_fast_tx_get(sdata, skb->data);
+       ether_addr_copy(key.addr, skb->data);
+       if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr))
+               key.type = MESH_FAST_TX_TYPE_PROXIED;
+       entry = mesh_fast_tx_get(sdata, &key);
        if (!entry)
                return false;
 
index d913ce7ba72ef897fb6857f55df3fb20bc871b5e..3f9664e4e00c6c2e51faaa43d1a23860a6d22e4c 100644 (file)
@@ -134,10 +134,39 @@ struct mesh_path {
 #define MESH_FAST_TX_CACHE_THRESHOLD_SIZE      384
 #define MESH_FAST_TX_CACHE_TIMEOUT             8000 /* msecs */
 
+/**
+ * enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type
+ *
+ * @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA
+ * @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged)
+ * @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point
+ * @NUM_MESH_FAST_TX_TYPE: number of entry types
+ */
+enum ieee80211_mesh_fast_tx_type {
+       MESH_FAST_TX_TYPE_LOCAL,
+       MESH_FAST_TX_TYPE_PROXIED,
+       MESH_FAST_TX_TYPE_FORWARDED,
+
+       /* must be last */
+       NUM_MESH_FAST_TX_TYPE
+};
+
+
+/**
+ * struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key
+ *
+ * @addr: The Ethernet DA for this entry
+ * @type: cache entry type
+ */
+struct ieee80211_mesh_fast_tx_key {
+       u8 addr[ETH_ALEN] __aligned(2);
+       u16 type;
+};
+
 /**
  * struct ieee80211_mesh_fast_tx - cached mesh fast tx entry
  * @rhash: rhashtable pointer
- * @addr_key: The Ethernet DA which is the key for this entry
+ * @key: the lookup key for this cache entry
  * @fast_tx: base fast_tx data
  * @hdr: cached mesh and rfc1042 headers
  * @hdrlen: length of mesh + rfc1042
@@ -148,7 +177,7 @@ struct mesh_path {
  */
 struct ieee80211_mesh_fast_tx {
        struct rhash_head rhash;
-       u8 addr_key[ETH_ALEN] __aligned(2);
+       struct ieee80211_mesh_fast_tx_key key;
 
        struct ieee80211_fast_tx fast_tx;
        u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)];
@@ -334,7 +363,8 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
 
 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
 struct ieee80211_mesh_fast_tx *
-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr);
+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_mesh_fast_tx_key *key);
 bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
                              struct sk_buff *skb, u32 ctrl_flags);
 void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
index 91b55d6a68b9739f9d22786bf403c801fc34d864..a6b62169f08483c5aa481f4f8f59f67fa56a4ef7 100644 (file)
@@ -37,8 +37,8 @@ static const struct rhashtable_params mesh_rht_params = {
 static const struct rhashtable_params fast_tx_rht_params = {
        .nelem_hint = 10,
        .automatic_shrinking = true,
-       .key_len = ETH_ALEN,
-       .key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key),
+       .key_len = sizeof_field(struct ieee80211_mesh_fast_tx, key),
+       .key_offset = offsetof(struct ieee80211_mesh_fast_tx, key),
        .head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash),
        .hashfn = mesh_table_hash,
 };
@@ -431,20 +431,21 @@ static void mesh_fast_tx_entry_free(struct mesh_tx_cache *cache,
 }
 
 struct ieee80211_mesh_fast_tx *
-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_mesh_fast_tx_key *key)
 {
        struct ieee80211_mesh_fast_tx *entry;
        struct mesh_tx_cache *cache;
 
        cache = &sdata->u.mesh.tx_cache;
-       entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
+       entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
        if (!entry)
                return NULL;
 
        if (!(entry->mpath->flags & MESH_PATH_ACTIVE) ||
            mpath_expired(entry->mpath)) {
                spin_lock_bh(&cache->walk_lock);
-               entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
+               entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
                if (entry)
                    mesh_fast_tx_entry_free(cache, entry);
                spin_unlock_bh(&cache->walk_lock);
@@ -489,18 +490,24 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
        if (!sta)
                return;
 
+       build.key.type = MESH_FAST_TX_TYPE_LOCAL;
        if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) {
                /* This is required to keep the mppath alive */
                mppath = mpp_path_lookup(sdata, meshhdr->eaddr1);
                if (!mppath)
                        return;
                build.mppath = mppath;
+               if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
+                       build.key.type = MESH_FAST_TX_TYPE_PROXIED;
        } else if (ieee80211_has_a4(hdr->frame_control)) {
                mppath = mpath;
        } else {
                return;
        }
 
+       if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
+               build.key.type = MESH_FAST_TX_TYPE_FORWARDED;
+
        /* rate limit, in case fast xmit can't be enabled */
        if (mppath->fast_tx_check == jiffies)
                return;
@@ -547,7 +554,7 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       memcpy(build.addr_key, mppath->dst, ETH_ALEN);
+       memcpy(build.key.addr, mppath->dst, ETH_ALEN);
        build.timestamp = jiffies;
        build.fast_tx.band = info->band;
        build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3);
@@ -646,12 +653,18 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata,
                             const u8 *addr)
 {
        struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache;
+       struct ieee80211_mesh_fast_tx_key key = {};
        struct ieee80211_mesh_fast_tx *entry;
+       int i;
 
+       ether_addr_copy(key.addr, addr);
        spin_lock_bh(&cache->walk_lock);
-       entry = rhashtable_lookup_fast(&cache->rht, addr, fast_tx_rht_params);
-       if (entry)
-               mesh_fast_tx_entry_free(cache, entry);
+       for (i = 0; i < NUM_MESH_FAST_TX_TYPE; i++) {
+               key.type = i;
+               entry = rhashtable_lookup_fast(&cache->rht, &key, fast_tx_rht_params);
+               if (entry)
+                       mesh_fast_tx_entry_free(cache, entry);
+       }
        spin_unlock_bh(&cache->walk_lock);
 }
 
index 685185dc04f9700995677535ecd81f3b132ac85a..6e24864f9a40ba1b8d689263cf905cc0ff5d3d69 100644 (file)
@@ -2763,7 +2763,10 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
                               struct sk_buff *skb, int hdrlen)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       struct ieee80211_mesh_fast_tx *entry = NULL;
+       struct ieee80211_mesh_fast_tx_key key = {
+               .type = MESH_FAST_TX_TYPE_FORWARDED
+       };
+       struct ieee80211_mesh_fast_tx *entry;
        struct ieee80211s_hdr *mesh_hdr;
        struct tid_ampdu_tx *tid_tx;
        struct sta_info *sta;
@@ -2772,9 +2775,13 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
 
        mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
        if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
-               entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
+               ether_addr_copy(key.addr, mesh_hdr->eaddr1);
        else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
-               entry = mesh_fast_tx_get(sdata, skb->data);
+               ether_addr_copy(key.addr, skb->data);
+       else
+               return false;
+
+       entry = mesh_fast_tx_get(sdata, &key);
        if (!entry)
                return false;