Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <nbd@nbd.name>
- Loading branch information
Showing
1 changed file
with
219 additions
and
0 deletions.
There are no files selected for viewing
219 changes: 219 additions & 0 deletions
219
...el/mac80211/patches/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
From: Felix Fietkau <nbd@nbd.name> | ||
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 <nbd@nbd.name> | ||
--- | ||
|
||
--- 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; | ||
|