linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michael Braun <michael-dev@fami-braun.de>
To: johannes@sipsolutions.net
Cc: Michael Braun <michael-dev@fami-braun.de>,
	linux-wireless@vger.kernel.org
Subject: [PATCH 3/3] mac80211: cache the only AP_VLAN station
Date: Sun, 25 Sep 2016 18:39:56 +0200	[thread overview]
Message-ID: <1474821596-12155-4-git-send-email-michael-dev@fami-braun.de> (raw)
In-Reply-To: <1474821596-12155-1-git-send-email-michael-dev@fami-braun.de>

If an AP_VLAN is only used with one station, cache a pointer to this station to
avoid lookup. This should speed up station lookup when there is only one
station assigned to the AP_VLAN interface, e.g. when using hostapd with
per_sta_vif.

Assigning only one station per AP_VLAN interfaces enables bridge IGMP snooping
to track multicast subscriptions by station to selectively forward to only
those stations that subscribed.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
 net/mac80211/cfg.c         | 10 ++++++++--
 net/mac80211/ieee80211_i.h | 14 ++++++++++----
 net/mac80211/sta_info.c    | 33 +++++++++++++++++++++++++++++++--
 net/mac80211/tx.c          |  5 +++++
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 078e837..a69e6f2 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -67,6 +67,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 	if (type == NL80211_IFTYPE_AP_VLAN &&
 	    params && params->use_4addr == 0) {
 		RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
+		RCU_INIT_POINTER(sdata->u.vlan.sta0, NULL);
 		ieee80211_check_fast_rx_iface(sdata);
 	} else if (type == NL80211_IFTYPE_STATION &&
 		   params && params->use_4addr >= 0) {
@@ -1379,8 +1380,13 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 		sta->sdata = vlansdata;
 		ieee80211_check_fast_xmit(sta);
 
-		if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-			ieee80211_vif_inc_num_mcast(sta->sdata);
+		if (test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
+		    ieee80211_vif_inc_num_mcast(sta->sdata) == 1 &&
+		    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+			rcu_assign_pointer(vlansdata->u.vlan.sta0, sta);
+		else if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			 test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+			RCU_INIT_POINTER(vlansdata->u.vlan.sta0, NULL);
 
 		ieee80211_send_layer2_update(sta);
 	}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7b3de28..48a141f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -307,6 +307,8 @@ struct ieee80211_if_vlan {
 
 	/* used for all tx if the VLAN is configured to 4-addr mode */
 	struct sta_info __rcu *sta;
+	/* the one and only authenticated station in non 4-addr mode if set */
+	struct sta_info __rcu *sta0;
 	atomic_t num_mcast_sta_if; /* number of stations receiving multicast */
 };
 
@@ -1499,21 +1501,25 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
 	return false;
 }
 
-static inline void
+static inline int
 ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata)
 {
+	int ret;
+
 	if (sdata->vif.type != NL80211_IFTYPE_AP &&
 	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
-		return;
+		return -1;
 
 	if (sdata->vif.type == NL80211_IFTYPE_AP)
-		atomic_inc(&sdata->u.ap.num_mcast_sta_if);
+		ret = atomic_inc_return(&sdata->u.ap.num_mcast_sta_if);
 	else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-		atomic_inc(&sdata->u.vlan.num_mcast_sta_if);
+		ret = atomic_inc_return(&sdata->u.vlan.num_mcast_sta_if);
 
 	if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
 	    !sdata->u.vlan.sta) /* except 4addr mode */
 		atomic_inc(&sdata->bss->num_mcast_sta);
+
+	return ret;
 }
 
 static inline void
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 216ef65..d1c5d96 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -162,11 +162,28 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 			      const u8 *addr)
 {
 	struct ieee80211_local *local = sdata->local;
-	struct sta_info *sta;
+	struct sta_info *sta = NULL;
 	struct rhash_head *tmp;
 	const struct bucket_table *tbl;
 
 	rcu_read_lock();
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    !sdata->u.vlan.sta)
+		sta = rcu_dereference(sdata->u.vlan.sta0);
+
+	WARN_ONCE((sta && sta->sdata != sdata),
+		  "sdata->u.vlan.sta0->sdata != sdata");
+
+	if (sta && sta->sdata == sdata &&
+	    ether_addr_equal(sta->sta.addr, addr)) {
+		rcu_read_unlock();
+		/* this is safe as the caller must already hold
+		 * another rcu read section or the mutex
+		 */
+		return sta;
+	}
+
 	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
 
 	for_each_sta_info(local, tbl, addr, sta, tmp) {
@@ -920,6 +937,10 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
 	    rcu_access_pointer(sdata->u.vlan.sta) == sta)
 		RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
 
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    rcu_access_pointer(sdata->u.vlan.sta0) == sta)
+		RCU_INIT_POINTER(sdata->u.vlan.sta0, NULL);
+
 	return 0;
 }
 
@@ -1883,6 +1904,9 @@ int sta_info_move_state(struct sta_info *sta,
 				ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
 		} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
 			ieee80211_vif_dec_num_mcast(sta->sdata);
+			if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			    rcu_access_pointer(sta->sdata->u.vlan.sta0) == sta)
+				RCU_INIT_POINTER(sta->sdata->u.vlan.sta0, NULL);
 			clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
 			ieee80211_clear_fast_xmit(sta);
 			ieee80211_clear_fast_rx(sta);
@@ -1890,7 +1914,12 @@ int sta_info_move_state(struct sta_info *sta,
 		break;
 	case IEEE80211_STA_AUTHORIZED:
 		if (sta->sta_state == IEEE80211_STA_ASSOC) {
-			ieee80211_vif_inc_num_mcast(sta->sdata);
+			if (ieee80211_vif_inc_num_mcast(sta->sdata) == 1 &&
+			    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+				rcu_assign_pointer(sta->sdata->u.vlan.sta0,
+						   sta);
+			else if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+				RCU_INIT_POINTER(sta->sdata->u.vlan.sta0, NULL);
 			set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
 			ieee80211_check_fast_xmit(sta);
 			ieee80211_check_fast_rx(sta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9c82fd8..c06d5f9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1808,6 +1808,7 @@ ieee80211_tx_multicast_to_unicast(struct ieee80211_sub_if_data *sdata,
 		sta = rcu_dereference(sdata->u.vlan.sta);
 		if (sta) /* 4addr */
 			return 0;
+		prev = rcu_dereference(sdata->u.vlan.sta0);
 	case NL80211_IFTYPE_AP:
 		break;
 	default:
@@ -1839,6 +1840,9 @@ ieee80211_tx_multicast_to_unicast(struct ieee80211_sub_if_data *sdata,
 		return 0;
 	}
 
+	if (prev)
+		goto skip_lookup;
+
 	/* clone packets and update destination mac */
 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
 		if (sdata != sta->sdata)
@@ -1862,6 +1866,7 @@ ieee80211_tx_multicast_to_unicast(struct ieee80211_sub_if_data *sdata,
 		prev = sta;
 	}
 
+skip_lookup:
 	if (likely(prev)) {
 		ieee80211_tx_dnat(skb, prev);
 		return 0;
-- 
2.1.4

  parent reply	other threads:[~2016-09-25 16:40 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-25 16:39 [PATCH 0/3] mac80211: multicast with AP_VLAN optimizations Michael Braun
2016-09-25 16:39 ` [PATCH 1/3] mac80211: filter multicast data packets on AP / AP_VLAN Michael Braun
2016-09-30  7:20   ` Johannes Berg
2016-09-25 16:39 ` [PATCH 2/3] mac80211: multicast to unicast conversion Michael Braun
2016-09-30  7:29   ` Johannes Berg
2016-10-04  4:36     ` M. Braun
2016-10-04  6:56       ` Johannes Berg
2016-09-25 16:39 ` Michael Braun [this message]
2016-09-30  9:47   ` [PATCH 3/3] mac80211: cache the only AP_VLAN station Johannes Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1474821596-12155-4-git-send-email-michael-dev@fami-braun.de \
    --to=michael-dev@fami-braun.de \
    --cc=johannes@sipsolutions.net \
    --cc=linux-wireless@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).