Skip to content

Commit 8d1f7ec

Browse files
committed
mac80211: defer tailroom counter manipulation when roaming
During roaming, the crypto_tx_tailroom_needed_cnt counter will often take values 2,1,0,1,2 because first keys are removed and then new keys are added. This is inefficient because during the 0->1 transition, synchronize_net must be called to avoid packet races, although typically no packets would be flowing during that time. To avoid that, defer the decrement (2->1, 1->0) when keys are removed (by half a second). This means the counter will really have the values 2,2,2,3,4 ... 2, thus never reaching 0 and having to do the 0->1 transition. Note that this patch entirely disregards the drivers for which this optimisation was done to start with, for them the key removal itself will be expensive because it has to synchronize_net() after the counter is incremented to remove the key from HW crypto. For them the sequence will look like this: 0,1,0,1,0,1,0,1,0 (*) which is clearly a lot more inefficient. This could be addressed separately, during key removal the 0->1->0 sequence isn't necessary. (*) it starts at 0 because HW crypto is on, then goes to 1 when HW crypto is disabled for a key, then back to 0 because the key is deleted; this happens for both keys in the example. When new keys are added, it goes to 1 first because they're added in software; when a key is moved to hardware it goes back to 0 Signed-off-by: Johannes Berg <[email protected]>
1 parent a871210 commit 8d1f7ec

File tree

6 files changed

+68
-11
lines changed

6 files changed

+68
-11
lines changed

net/mac80211/cfg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
254254
goto out_unlock;
255255
}
256256

257-
__ieee80211_key_free(key);
257+
__ieee80211_key_free(key, true);
258258

259259
ret = 0;
260260
out_unlock:

net/mac80211/ieee80211_i.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,8 @@ struct ieee80211_sub_if_data {
680680

681681
/* count for keys needing tailroom space allocation */
682682
int crypto_tx_tailroom_needed_cnt;
683+
int crypto_tx_tailroom_pending_dec;
684+
struct delayed_work dec_tailroom_needed_wk;
683685

684686
struct net_device *dev;
685687
struct ieee80211_local *local;

net/mac80211/iface.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
15431543
INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
15441544
INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work,
15451545
ieee80211_dfs_cac_timer_work);
1546+
INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk,
1547+
ieee80211_delayed_tailroom_dec);
15461548

15471549
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
15481550
struct ieee80211_supported_band *sband;

net/mac80211/key.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
397397
return key;
398398
}
399399

400-
static void __ieee80211_key_destroy(struct ieee80211_key *key)
400+
static void __ieee80211_key_destroy(struct ieee80211_key *key,
401+
bool delay_tailroom)
401402
{
402403
if (!key)
403404
return;
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
416417
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
417418
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
418419
if (key->local) {
420+
struct ieee80211_sub_if_data *sdata = key->sdata;
421+
419422
ieee80211_debugfs_key_remove(key);
420-
key->sdata->crypto_tx_tailroom_needed_cnt--;
423+
424+
if (delay_tailroom) {
425+
/* see ieee80211_delayed_tailroom_dec */
426+
sdata->crypto_tx_tailroom_pending_dec++;
427+
schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
428+
HZ/2);
429+
} else {
430+
sdata->crypto_tx_tailroom_needed_cnt--;
431+
}
421432
}
422433

423434
kfree(key);
@@ -452,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
452463
increment_tailroom_need_count(sdata);
453464

454465
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
455-
__ieee80211_key_destroy(old_key);
466+
__ieee80211_key_destroy(old_key, true);
456467

457468
ieee80211_debugfs_key_add(key);
458469

@@ -463,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
463474
return ret;
464475
}
465476

466-
void __ieee80211_key_free(struct ieee80211_key *key)
477+
void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
467478
{
468479
if (!key)
469480
return;
@@ -475,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key)
475486
__ieee80211_key_replace(key->sdata, key->sta,
476487
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
477488
key, NULL);
478-
__ieee80211_key_destroy(key);
489+
__ieee80211_key_destroy(key, delay_tailroom);
479490
}
480491

481492
void ieee80211_key_free(struct ieee80211_local *local,
482493
struct ieee80211_key *key)
483494
{
484495
mutex_lock(&local->key_mtx);
485-
__ieee80211_key_free(key);
496+
__ieee80211_key_free(key, true);
486497
mutex_unlock(&local->key_mtx);
487498
}
488499

@@ -544,18 +555,56 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
544555
{
545556
struct ieee80211_key *key, *tmp;
546557

558+
cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
559+
547560
mutex_lock(&sdata->local->key_mtx);
548561

562+
sdata->crypto_tx_tailroom_needed_cnt -=
563+
sdata->crypto_tx_tailroom_pending_dec;
564+
sdata->crypto_tx_tailroom_pending_dec = 0;
565+
549566
ieee80211_debugfs_key_remove_mgmt_default(sdata);
550567

551568
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
552-
__ieee80211_key_free(key);
569+
__ieee80211_key_free(key, false);
553570

554571
ieee80211_debugfs_key_update_default(sdata);
555572

573+
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
574+
sdata->crypto_tx_tailroom_pending_dec);
575+
556576
mutex_unlock(&sdata->local->key_mtx);
557577
}
558578

579+
void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
580+
{
581+
struct ieee80211_sub_if_data *sdata;
582+
583+
sdata = container_of(wk, struct ieee80211_sub_if_data,
584+
dec_tailroom_needed_wk.work);
585+
586+
/*
587+
* The reason for the delayed tailroom needed decrementing is to
588+
* make roaming faster: during roaming, all keys are first deleted
589+
* and then new keys are installed. The first new key causes the
590+
* crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
591+
* the cost of synchronize_net() (which can be slow). Avoid this
592+
* by deferring the crypto_tx_tailroom_needed_cnt decrementing on
593+
* key removal for a while, so if we roam the value is larger than
594+
* zero and no 0->1 transition happens.
595+
*
596+
* The cost is that if the AP switching was from an AP with keys
597+
* to one without, we still allocate tailroom while it would no
598+
* longer be needed. However, in the typical (fast) roaming case
599+
* within an ESS this usually won't happen.
600+
*/
601+
602+
mutex_lock(&sdata->local->key_mtx);
603+
sdata->crypto_tx_tailroom_needed_cnt -=
604+
sdata->crypto_tx_tailroom_pending_dec;
605+
sdata->crypto_tx_tailroom_pending_dec = 0;
606+
mutex_unlock(&sdata->local->key_mtx);
607+
}
559608

560609
void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
561610
const u8 *replay_ctr, gfp_t gfp)

net/mac80211/key.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
134134
int __must_check ieee80211_key_link(struct ieee80211_key *key,
135135
struct ieee80211_sub_if_data *sdata,
136136
struct sta_info *sta);
137-
void __ieee80211_key_free(struct ieee80211_key *key);
137+
void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
138138
void ieee80211_key_free(struct ieee80211_local *local,
139139
struct ieee80211_key *key);
140140
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
@@ -147,4 +147,6 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
147147
#define key_mtx_dereference(local, ref) \
148148
rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
149149

150+
void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
151+
150152
#endif /* IEEE80211_KEY_H */

net/mac80211/sta_info.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,9 +794,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
794794

795795
mutex_lock(&local->key_mtx);
796796
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
797-
__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
797+
__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]),
798+
true);
798799
if (sta->ptk)
799-
__ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
800+
__ieee80211_key_free(key_mtx_dereference(local, sta->ptk),
801+
true);
800802
mutex_unlock(&local->key_mtx);
801803

802804
sta->dead = true;

0 commit comments

Comments
 (0)