aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/key.c
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/mac80211/key.c
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/mac80211/key.c')
-rw-r--r--net/mac80211/key.c63
1 files changed, 56 insertions, 7 deletions
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)