batman-adv: Allow to use rntl_link for device creation/deletion
authorSven Eckelmann <sven@narfation.org>
Mon, 11 Feb 2013 09:10:26 +0000 (17:10 +0800)
committerAntonio Quartulli <ordex@autistici.org>
Wed, 27 Mar 2013 09:27:34 +0000 (10:27 +0100)
The sysfs configuration interface of batman-adv to add/remove soft-interfaces
is not deadlock free and doesn't follow the currently common way to create new
virtual interfaces.

An additional interface though rtnl_link is introduced which provides easy device
creation/deletion with tools like "ip":

$ ip link add dev bat0 type batadv
$ ip link del dev bat0

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.h

index 0495a7d..62b1f89 100644 (file)
@@ -71,6 +71,7 @@ static int __init batadv_init(void)
        batadv_debugfs_init();
 
        register_netdevice_notifier(&batadv_hard_if_notifier);
+       rtnl_link_register(&batadv_link_ops);
 
        pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
                BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
@@ -81,6 +82,7 @@ static int __init batadv_init(void)
 static void __exit batadv_exit(void)
 {
        batadv_debugfs_destroy();
+       rtnl_link_unregister(&batadv_link_ops);
        unregister_netdevice_notifier(&batadv_hard_if_notifier);
        batadv_hardif_remove_interfaces();
 
index 0afd4ee..a9e12e6 100644 (file)
@@ -152,6 +152,7 @@ enum batadv_uev_type {
 #include <linux/percpu.h>
 #include <linux/slab.h>
 #include <net/sock.h>          /* struct sock */
+#include <net/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/seq_file.h>
 #include "types.h"
index bc77a5b..545c863 100644 (file)
@@ -570,6 +570,8 @@ struct net_device *batadv_softif_create(const char *name)
        if (!soft_iface)
                return NULL;
 
+       soft_iface->rtnl_link_ops = &batadv_link_ops;
+
        ret = register_netdevice(soft_iface);
        if (ret < 0) {
                pr_err("Unable to register the batman interface '%s': %i\n",
@@ -592,6 +594,26 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface)
        queue_work(batadv_event_workqueue, &bat_priv->cleanup_work);
 }
 
+/**
+ * batadv_softif_destroy_netlink - deletion of batadv_soft_interface via netlink
+ * @soft_iface: the to-be-removed batman-adv interface
+ * @head: list pointer
+ */
+static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
+                                         struct list_head *head)
+{
+       struct batadv_hard_iface *hard_iface;
+
+       list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->soft_iface == soft_iface)
+                       batadv_hardif_disable_interface(hard_iface,
+                                                       BATADV_IF_CLEANUP_KEEP);
+       }
+
+       batadv_sysfs_del_meshif(soft_iface);
+       unregister_netdevice_queue(soft_iface, head);
+}
+
 int batadv_softif_is_valid(const struct net_device *net_dev)
 {
        if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
@@ -600,6 +622,13 @@ int batadv_softif_is_valid(const struct net_device *net_dev)
        return 0;
 }
 
+struct rtnl_link_ops batadv_link_ops __read_mostly = {
+       .kind           = "batadv",
+       .priv_size      = sizeof(struct batadv_priv),
+       .setup          = batadv_softif_init_early,
+       .dellink        = batadv_softif_destroy_netlink,
+};
+
 /* ethtool */
 static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
index 49bc66b..2f2472c 100644 (file)
@@ -27,5 +27,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
 struct net_device *batadv_softif_create(const char *name);
 void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
 int batadv_softif_is_valid(const struct net_device *net_dev);
+extern struct rtnl_link_ops batadv_link_ops;
 
 #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */