aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-22 18:59:03 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-06 10:36:00 -0500
commit8d1f7ecd2af55c0c82ffd2bff0ef0b26f16ea69f (patch)
tree51e4fe05518ea5cb51f938c4e9aa756115c7c949 /net
parenta87121051ce80831a302c67286119013104f7a5a (diff)
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 <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/key.c63
-rw-r--r--net/mac80211/key.h4
-rw-r--r--net/mac80211/sta_info.c6
6 files changed, 68 insertions, 11 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f9cbdc29946d..8baa561c8f5b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
254 goto out_unlock; 254 goto out_unlock;
255 } 255 }
256 256
257 __ieee80211_key_free(key); 257 __ieee80211_key_free(key, true);
258 258
259 ret = 0; 259 ret = 0;
260 out_unlock: 260 out_unlock:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0acc07b852a9..54d09ec3fe68 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -680,6 +680,8 @@ struct ieee80211_sub_if_data {
680 680
681 /* count for keys needing tailroom space allocation */ 681 /* count for keys needing tailroom space allocation */
682 int crypto_tx_tailroom_needed_cnt; 682 int crypto_tx_tailroom_needed_cnt;
683 int crypto_tx_tailroom_pending_dec;
684 struct delayed_work dec_tailroom_needed_wk;
683 685
684 struct net_device *dev; 686 struct net_device *dev;
685 struct ieee80211_local *local; 687 struct ieee80211_local *local;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1ee10cd1d5b6..8e0bf34f3f68 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1543,6 +1543,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1543 INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); 1543 INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
1544 INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, 1544 INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work,
1545 ieee80211_dfs_cac_timer_work); 1545 ieee80211_dfs_cac_timer_work);
1546 INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk,
1547 ieee80211_delayed_tailroom_dec);
1546 1548
1547 for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 1549 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
1548 struct ieee80211_supported_band *sband; 1550 struct ieee80211_supported_band *sband;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 6eb4888a70ed..99e9f6ae6a54 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
397 return key; 397 return key;
398} 398}
399 399
400static void __ieee80211_key_destroy(struct ieee80211_key *key) 400static void __ieee80211_key_destroy(struct ieee80211_key *key,
401 bool delay_tailroom)
401{ 402{
402 if (!key) 403 if (!key)
403 return; 404 return;
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
416 if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) 417 if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
417 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); 418 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
418 if (key->local) { 419 if (key->local) {
420 struct ieee80211_sub_if_data *sdata = key->sdata;
421
419 ieee80211_debugfs_key_remove(key); 422 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 }
421 } 432 }
422 433
423 kfree(key); 434 kfree(key);
@@ -452,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
452 increment_tailroom_need_count(sdata); 463 increment_tailroom_need_count(sdata);
453 464
454 __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); 465 __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
455 __ieee80211_key_destroy(old_key); 466 __ieee80211_key_destroy(old_key, true);
456 467
457 ieee80211_debugfs_key_add(key); 468 ieee80211_debugfs_key_add(key);
458 469
@@ -463,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
463 return ret; 474 return ret;
464} 475}
465 476
466void __ieee80211_key_free(struct ieee80211_key *key) 477void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
467{ 478{
468 if (!key) 479 if (!key)
469 return; 480 return;
@@ -475,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key)
475 __ieee80211_key_replace(key->sdata, key->sta, 486 __ieee80211_key_replace(key->sdata, key->sta,
476 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, 487 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
477 key, NULL); 488 key, NULL);
478 __ieee80211_key_destroy(key); 489 __ieee80211_key_destroy(key, delay_tailroom);
479} 490}
480 491
481void ieee80211_key_free(struct ieee80211_local *local, 492void ieee80211_key_free(struct ieee80211_local *local,
482 struct ieee80211_key *key) 493 struct ieee80211_key *key)
483{ 494{
484 mutex_lock(&local->key_mtx); 495 mutex_lock(&local->key_mtx);
485 __ieee80211_key_free(key); 496 __ieee80211_key_free(key, true);
486 mutex_unlock(&local->key_mtx); 497 mutex_unlock(&local->key_mtx);
487} 498}
488 499
@@ -544,18 +555,56 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
544{ 555{
545 struct ieee80211_key *key, *tmp; 556 struct ieee80211_key *key, *tmp;
546 557
558 cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
559
547 mutex_lock(&sdata->local->key_mtx); 560 mutex_lock(&sdata->local->key_mtx);
548 561
562 sdata->crypto_tx_tailroom_needed_cnt -=
563 sdata->crypto_tx_tailroom_pending_dec;
564 sdata->crypto_tx_tailroom_pending_dec = 0;
565
549 ieee80211_debugfs_key_remove_mgmt_default(sdata); 566 ieee80211_debugfs_key_remove_mgmt_default(sdata);
550 567
551 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 568 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
552 __ieee80211_key_free(key); 569 __ieee80211_key_free(key, false);
553 570
554 ieee80211_debugfs_key_update_default(sdata); 571 ieee80211_debugfs_key_update_default(sdata);
555 572
573 WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
574 sdata->crypto_tx_tailroom_pending_dec);
575
556 mutex_unlock(&sdata->local->key_mtx); 576 mutex_unlock(&sdata->local->key_mtx);
557} 577}
558 578
579void 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}
559 608
560void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, 609void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
561 const u8 *replay_ctr, gfp_t gfp) 610 const u8 *replay_ctr, gfp_t gfp)
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 8b037307a586..2a682d81cee9 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
134int __must_check ieee80211_key_link(struct ieee80211_key *key, 134int __must_check ieee80211_key_link(struct ieee80211_key *key,
135 struct ieee80211_sub_if_data *sdata, 135 struct ieee80211_sub_if_data *sdata,
136 struct sta_info *sta); 136 struct sta_info *sta);
137void __ieee80211_key_free(struct ieee80211_key *key); 137void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
138void ieee80211_key_free(struct ieee80211_local *local, 138void ieee80211_key_free(struct ieee80211_local *local,
139 struct ieee80211_key *key); 139 struct ieee80211_key *key);
140void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, 140void 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);
147#define key_mtx_dereference(local, ref) \ 147#define key_mtx_dereference(local, ref) \
148 rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) 148 rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
149 149
150void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
151
150#endif /* IEEE80211_KEY_H */ 152#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a79ce820cb50..0141e4951adf 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -794,9 +794,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
794 794
795 mutex_lock(&local->key_mtx); 795 mutex_lock(&local->key_mtx);
796 for (i = 0; i < NUM_DEFAULT_KEYS; i++) 796 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);
798 if (sta->ptk) 799 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);
800 mutex_unlock(&local->key_mtx); 802 mutex_unlock(&local->key_mtx);
801 803
802 sta->dead = true; 804 sta->dead = true;