mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-28 09:39:00 +00:00
f861292abc
Signed-off-by: Felix Fietkau <nbd@nbd.name>
220 lines
7.4 KiB
Diff
220 lines
7.4 KiB
Diff
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
|
|
@@ -765,6 +765,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);
|
|
@@ -800,7 +803,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
|
|
@@ -134,9 +134,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
|
|
@@ -147,7 +171,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 +358,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
|
|
@@ -2727,7 +2727,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;
|
|
@@ -2736,9 +2739,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;
|
|
|