aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-06-21 19:55:04 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-06-24 02:06:26 +0200
commit152f93e06d82a9c9d35ee74f216728bc10419415 (patch)
tree3316a8f3ff7b99bb869faa391e392a9b0618d485 /src
parentdevice: netdevice destruction logic change for 4.12 (diff)
downloadwireguard-monolithic-historical-152f93e06d82a9c9d35ee74f216728bc10419415.tar.xz
wireguard-monolithic-historical-152f93e06d82a9c9d35ee74f216728bc10419415.zip
device: only use one sleep notifier
This greatly improves performance when adding and removing interfaces, since the power registration function does a linear search each time.
Diffstat (limited to 'src')
-rw-r--r--src/device.c45
-rw-r--r--src/device.h5
2 files changed, 27 insertions, 23 deletions
diff --git a/src/device.c b/src/device.c
index 88c7e7a..7a2948a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -26,6 +26,8 @@
#include <net/netfilter/nf_nat_core.h>
#endif
+static LIST_HEAD(device_list);
+
static int open(struct net_device *dev)
{
int ret;
@@ -68,19 +70,27 @@ static int open(struct net_device *dev)
#ifdef CONFIG_PM_SLEEP
static int suspending_clear_noise_peers(struct notifier_block *nb, unsigned long action, void *data)
{
- struct wireguard_device *wg = container_of(nb, struct wireguard_device, clear_peers_on_suspend);
+ struct wireguard_device *wg;
struct wireguard_peer *peer, *temp;
- if (action == PM_HIBERNATION_PREPARE || action == PM_SUSPEND_PREPARE) {
+
+ if (action != PM_HIBERNATION_PREPARE && action != PM_SUSPEND_PREPARE)
+ return 0;
+
+ rtnl_lock();
+ list_for_each_entry (wg, &device_list, device_list) {
peer_for_each (wg, peer, temp, true) {
noise_handshake_clear(&peer->handshake);
noise_keypairs_clear(&peer->keypairs);
if (peer->timers_enabled)
del_timer(&peer->timer_kill_ephemerals);
}
- rcu_barrier_bh();
}
+ rtnl_unlock();
+ rcu_barrier_bh();
+
return 0;
}
+static struct notifier_block clear_peers_on_suspend = { .notifier_call = suspending_clear_noise_peers };
#endif
static int stop(struct net_device *dev)
@@ -227,6 +237,9 @@ static void destruct(struct net_device *dev)
{
struct wireguard_device *wg = netdev_priv(dev);
+ rtnl_lock();
+ list_del(&wg->device_list);
+ rtnl_unlock();
mutex_lock(&wg->device_update_lock);
peer_remove_all(wg);
wg->incoming_port = 0;
@@ -242,9 +255,6 @@ static void destruct(struct net_device *dev)
skb_queue_purge(&wg->incoming_handshakes);
socket_uninit(wg);
cookie_checker_uninit(&wg->cookie_checker);
-#ifdef CONFIG_PM_SLEEP
- unregister_pm_notifier(&wg->clear_peers_on_suspend);
-#endif
mutex_unlock(&wg->device_update_lock);
free_percpu(dev->tstats);
free_percpu(wg->incoming_handshakes_worker);
@@ -347,27 +357,16 @@ static int newlink(struct net *src_net, struct net_device *dev, struct nlattr *t
if (ret < 0)
goto error_8;
-#ifdef CONFIG_PM_SLEEP
- wg->clear_peers_on_suspend.notifier_call = suspending_clear_noise_peers;
- ret = register_pm_notifier(&wg->clear_peers_on_suspend);
- if (ret < 0)
- goto error_9;
-#endif
-
ret = register_netdevice(dev);
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
if (ret < 0)
- goto error_10;
+ goto error_9;
#endif
+ list_add(&wg->device_list, &device_list);
pr_debug("%s: Interface created\n", dev->name);
return ret;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
-error_10:
-#endif
-#ifdef CONFIG_PM_SLEEP
- unregister_pm_notifier(&wg->clear_peers_on_suspend);
error_9:
#endif
cookie_checker_uninit(&wg->cookie_checker);
@@ -401,11 +400,19 @@ static struct rtnl_link_ops link_ops __read_mostly = {
int __init device_init(void)
{
+#ifdef CONFIG_PM_SLEEP
+ int ret = register_pm_notifier(&clear_peers_on_suspend);
+ if (ret)
+ return ret;
+#endif
return rtnl_link_register(&link_ops);
}
void __exit device_uninit(void)
{
rtnl_link_unregister(&link_ops);
+#ifdef CONFIG_PM_SLEEP
+ unregister_pm_notifier(&clear_peers_on_suspend);
+#endif
rcu_barrier_bh();
}
diff --git a/src/device.h b/src/device.h
index f443191..5ba2c5d 100644
--- a/src/device.h
+++ b/src/device.h
@@ -14,7 +14,6 @@
#include <linux/mutex.h>
#include <linux/net.h>
#include <linux/padata.h>
-#include <linux/notifier.h>
struct wireguard_device;
struct handshake_worker {
@@ -23,6 +22,7 @@ struct handshake_worker {
};
struct wireguard_device {
+ struct list_head device_list;
struct sock __rcu *sock4, *sock6;
u16 incoming_port;
u32 fwmark;
@@ -39,9 +39,6 @@ struct wireguard_device {
struct list_head peer_list;
struct mutex device_update_lock;
struct mutex socket_update_lock;
-#ifdef CONFIG_PM_SLEEP
- struct notifier_block clear_peers_on_suspend;
-#endif
#ifdef CONFIG_WIREGUARD_PARALLEL
struct workqueue_struct *crypt_wq;
struct padata_instance *encrypt_pd, *decrypt_pd;