Commit 8c75cdcd authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

wifi: 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.

Fixes: d5edb9ae ("wifi: mac80211: mesh fast xmit support")
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://msgid.link/20240415121811.13391-1-nbd@nbd.name


[use sizeof_field() for key_len]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent feafe59c
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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;

+33 −3
Original line number Diff line number Diff line
@@ -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,
+22 −9
Original line number Diff line number Diff line
@@ -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);
	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);
}

+10 −3
Original line number Diff line number Diff line
@@ -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;