From c6509cc3b3e84b6b0a640280981d60090ad7871e Mon Sep 17 00:00:00 2001 From: Benjamin Beichler Date: Wed, 10 Jan 2018 17:42:52 +0100 Subject: [PATCH] mac80211_hwsim: add hashtable with mac address keys for faster lookup This patch adds a rhastable for mac address lookup of hwsim radios. This especially improve the speed on reception of a netlink message with a new frame. Although redundant, we keep holding a normal list for all radios, since the rhashtable_walk interface adds a lot of overhead for iterating over all radios and the doc of rhashtable recommend a redundant structure for stable walks in such situations. Since rhashtable is rcu protected we do not need a lock for delivering frames and thus improving this scenario. Signed-off-by: Benjamin Beichler [remove hash function, it would cause alignment issues] Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 50 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 78367373185f..9339615a46d3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "mac80211_hwsim.h" #define WARN_QUEUE 100 @@ -489,6 +490,7 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = { static spinlock_t hwsim_radio_lock; static LIST_HEAD(hwsim_radios); +static struct rhashtable hwsim_radios_rht; static int hwsim_radio_idx; static struct platform_driver mac80211_hwsim_driver = { @@ -499,6 +501,7 @@ static struct platform_driver mac80211_hwsim_driver = { struct mac80211_hwsim_data { struct list_head list; + struct rhash_head rht; struct ieee80211_hw *hw; struct device *dev; struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; @@ -573,6 +576,13 @@ struct mac80211_hwsim_data { u64 tx_failed; }; +static const struct rhashtable_params hwsim_rht_params = { + .nelem_hint = 2, + .automatic_shrinking = true, + .key_len = ETH_ALEN, + .key_offset = offsetof(struct mac80211_hwsim_data, addresses[1]), + .head_offset = offsetof(struct mac80211_hwsim_data, rht), +}; struct hwsim_radiotap_hdr { struct ieee80211_radiotap_header hdr; @@ -2731,6 +2741,15 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); spin_lock_bh(&hwsim_radio_lock); + err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, + hwsim_rht_params); + if (err < 0) { + pr_debug("mac80211_hwsim: radio index %d already present\n", + idx); + spin_unlock_bh(&hwsim_radio_lock); + goto failed_final_insert; + } + list_add_tail(&data->list, &hwsim_radios); spin_unlock_bh(&hwsim_radio_lock); @@ -2739,6 +2758,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, return idx; +failed_final_insert: + debugfs_remove_recursive(data->debugfs); + ieee80211_unregister_hw(data->hw); failed_hw: device_release_driver(data->dev); failed_bind: @@ -2874,22 +2896,9 @@ static void hwsim_mon_setup(struct net_device *dev) static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) { - struct mac80211_hwsim_data *data; - bool _found = false; - - spin_lock_bh(&hwsim_radio_lock); - list_for_each_entry(data, &hwsim_radios, list) { - if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) { - _found = true; - break; - } - } - spin_unlock_bh(&hwsim_radio_lock); - - if (!_found) - return NULL; - - return data; + return rhashtable_lookup_fast(&hwsim_radios_rht, + addr, + hwsim_rht_params); } static void hwsim_register_wmediumd(struct net *net, u32 portid) @@ -3191,6 +3200,8 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) continue; list_del(&data->list); + rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, + hwsim_rht_params); spin_unlock_bh(&hwsim_radio_lock); mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), info); @@ -3346,6 +3357,8 @@ static void remove_user_radios(u32 portid) list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { if (entry->destroy_on_close && entry->portid == portid) { list_del(&entry->list); + rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht, + hwsim_rht_params); INIT_WORK(&entry->destroy_work, destroy_radio); schedule_work(&entry->destroy_work); } @@ -3421,6 +3434,8 @@ static void __net_exit hwsim_exit_net(struct net *net) continue; list_del(&data->list); + rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, + hwsim_rht_params); INIT_WORK(&data->destroy_work, destroy_radio); schedule_work(&data->destroy_work); } @@ -3454,6 +3469,8 @@ static int __init init_mac80211_hwsim(void) spin_lock_init(&hwsim_radio_lock); + rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); + err = register_pernet_device(&hwsim_net_ops); if (err) return err; @@ -3592,6 +3609,7 @@ static void __exit exit_mac80211_hwsim(void) hwsim_exit_netlink(); mac80211_hwsim_free(); + rhashtable_destroy(&hwsim_radios_rht); unregister_netdev(hwsim_mon); platform_driver_unregister(&mac80211_hwsim_driver); unregister_pernet_device(&hwsim_net_ops); -- 2.45.2