From c8963580aaf6a1207367c809d1350557d6e075e9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 30 Jun 2023 13:18:31 +0200 Subject: [PATCH] mac80211: fix mesh fast tx cache issues Split the cache by tx type in order to avoid packet drop issues Signed-off-by: Felix Fietkau --- ...esh-fast-tx-cache-into-local-proxied.patch | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch diff --git a/package/kernel/mac80211/patches/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch b/package/kernel/mac80211/patches/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch new file mode 100644 index 0000000000..f7391a5809 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch @@ -0,0 +1,219 @@ +From: Felix Fietkau +Date: Fri, 30 Jun 2023 13:11:51 +0200 +Subject: [PATCH] mac80211: split mesh fast tx cache into + local/proxied/forwarded + +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. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -703,6 +703,9 @@ bool ieee80211_mesh_xmit_fast(struct iee + 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); +@@ -738,7 +741,10 @@ bool ieee80211_mesh_xmit_fast(struct iee + 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; + +--- a/net/mac80211/mesh.h ++++ b/net/mac80211/mesh.h +@@ -133,9 +133,33 @@ struct mesh_path { + #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 ++ */ ++enum ieee80211_mesh_fast_tx_type { ++ MESH_FAST_TX_TYPE_LOCAL, ++ MESH_FAST_TX_TYPE_PROXIED, ++ MESH_FAST_TX_TYPE_FORWARDED, ++}; ++ ++/** ++ * 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); ++ enum ieee80211_mesh_fast_tx_type 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 +@@ -146,7 +170,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)]; +@@ -329,7 +353,8 @@ void mesh_path_tx_root_frame(struct ieee + + 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, +--- a/net/mac80211/mesh_pathtbl.c ++++ b/net/mac80211/mesh_pathtbl.c +@@ -36,8 +36,8 @@ static const struct rhashtable_params me + 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(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, + }; +@@ -426,20 +426,21 @@ static void mesh_fast_tx_entry_free(stru + } + + 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); +@@ -484,18 +485,24 @@ void mesh_fast_tx_cache(struct ieee80211 + 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; +@@ -542,7 +549,7 @@ void mesh_fast_tx_cache(struct ieee80211 + } + } + +- 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); +@@ -644,13 +651,19 @@ void mesh_fast_tx_flush_addr(struct ieee + 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); + cache = &sdata->u.mesh.tx_cache; + spin_lock_bh(&cache->walk_lock); +- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params); +- if (entry) +- mesh_fast_tx_entry_free(cache, entry); ++ for (i = MESH_FAST_TX_TYPE_LOCAL; i < MESH_FAST_TX_TYPE_FORWARDED; i++) { ++ key.type = i; ++ 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); + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2726,7 +2726,10 @@ ieee80211_rx_mesh_fast_forward(struct ie + 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; +@@ -2735,9 +2738,13 @@ ieee80211_rx_mesh_fast_forward(struct ie + + 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; + -- 2.30.2