Hi,
here the third patch series to get the netlink interface creation into shape. Changes since v2: * Reference counting bugfix in batadv_add_slave() & batadv_del_slave() * Master settings & compat support
Kudos to Antonio for providing the compat support and debugging the interface to the bitter end!
Cheers, Marek
From: Sven Eckelmann sven@narfation.org
The initialization of an net_device object should be done in the init/constructor function and not from the outside after the register_netdevice was done to avoid race conditions.
Signed-off-by: Sven Eckelmann sven@narfation.org --- hard-interface.c | 5 ++ soft-interface.c | 169 ++++++++++++++++++++++++++---------------------------- 2 files changed, 86 insertions(+), 88 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index 368219e..da000e9 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -563,6 +563,11 @@ static int batadv_hard_if_event(struct notifier_block *this, struct batadv_hard_iface *primary_if = NULL; struct batadv_priv *bat_priv;
+ if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { + batadv_sysfs_add_meshif(net_dev); + return NOTIFY_DONE; + } + hard_iface = batadv_hardif_get_by_netdev(net_dev); if (!hard_iface && event == NETDEV_REGISTER) hard_iface = batadv_hardif_add_interface(net_dev); diff --git a/soft-interface.c b/soft-interface.c index f93ae42..c5cb0a7 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -402,55 +402,6 @@ static void batadv_set_lockdep_class(struct net_device *dev) }
/** - * batadv_softif_init - Late stage initialization of soft interface - * @dev: registered network device to modify - * - * Returns error code on failures - */ -static int batadv_softif_init(struct net_device *dev) -{ - batadv_set_lockdep_class(dev); - - return 0; -} - -static const struct net_device_ops batadv_netdev_ops = { - .ndo_init = batadv_softif_init, - .ndo_open = batadv_interface_open, - .ndo_stop = batadv_interface_release, - .ndo_get_stats = batadv_interface_stats, - .ndo_set_mac_address = batadv_interface_set_mac_addr, - .ndo_change_mtu = batadv_interface_change_mtu, - .ndo_start_xmit = batadv_interface_tx, - .ndo_validate_addr = eth_validate_addr -}; - -static void batadv_interface_setup(struct net_device *dev) -{ - struct batadv_priv *priv = netdev_priv(dev); - - ether_setup(dev); - - dev->netdev_ops = &batadv_netdev_ops; - dev->destructor = free_netdev; - dev->tx_queue_len = 0; - - /* can't call min_mtu, because the needed variables - * have not been initialized yet - */ - dev->mtu = ETH_DATA_LEN; - /* reserve more space in the skbuff for our header */ - dev->hard_header_len = BATADV_HEADER_LEN; - - /* generate random address */ - eth_hw_addr_random(dev); - - SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops); - - memset(priv, 0, sizeof(*priv)); -} - -/** * batadv_softif_destroy_finish - cleans up the remains of a softif * @work: work queue item * @@ -474,21 +425,22 @@ static void batadv_softif_destroy_finish(struct work_struct *work) rtnl_unlock(); }
-struct net_device *batadv_softif_create(const char *name) +/** + * batadv_softif_init_late - late stage initialization of soft interface + * @dev: registered network device to modify + * + * Returns error code on failures + */ +static int batadv_softif_init_late(struct net_device *dev) { - struct net_device *soft_iface; struct batadv_priv *bat_priv; int ret; size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM;
- soft_iface = alloc_netdev(sizeof(*bat_priv), name, - batadv_interface_setup); - - if (!soft_iface) - goto out; + batadv_set_lockdep_class(dev);
- bat_priv = netdev_priv(soft_iface); - bat_priv->soft_iface = soft_iface; + bat_priv = netdev_priv(dev); + bat_priv->soft_iface = dev; INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish);
/* batadv_interface_stats() needs to be available as soon as @@ -496,14 +448,7 @@ struct net_device *batadv_softif_create(const char *name) */ bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t)); if (!bat_priv->bat_counters) - goto free_soft_iface; - - ret = register_netdevice(soft_iface); - if (ret < 0) { - pr_err("Unable to register the batman interface '%s': %i\n", - name, ret); - goto free_bat_counters; - } + return -ENOMEM;
atomic_set(&bat_priv->aggregated_ogms, 1); atomic_set(&bat_priv->bonding, 0); @@ -541,41 +486,89 @@ struct net_device *batadv_softif_create(const char *name) bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0;
- ret = batadv_algo_select(bat_priv, batadv_routing_algo); - if (ret < 0) - goto unreg_soft_iface; - batadv_nc_init_bat_priv(bat_priv);
- ret = batadv_sysfs_add_meshif(soft_iface); + ret = batadv_algo_select(bat_priv, batadv_routing_algo); if (ret < 0) - goto unreg_soft_iface; + goto free_bat_counters;
- ret = batadv_debugfs_add_meshif(soft_iface); + ret = batadv_debugfs_add_meshif(dev); if (ret < 0) - goto unreg_sysfs; + goto free_bat_counters;
- ret = batadv_mesh_init(soft_iface); + ret = batadv_mesh_init(dev); if (ret < 0) goto unreg_debugfs;
- return soft_iface; + return 0;
unreg_debugfs: - batadv_debugfs_del_meshif(soft_iface); -unreg_sysfs: - batadv_sysfs_del_meshif(soft_iface); -unreg_soft_iface: - free_percpu(bat_priv->bat_counters); - unregister_netdevice(soft_iface); - return NULL; - + batadv_debugfs_del_meshif(dev); free_bat_counters: free_percpu(bat_priv->bat_counters); -free_soft_iface: - free_netdev(soft_iface); -out: - return NULL; + + return ret; +} + +static const struct net_device_ops batadv_netdev_ops = { + .ndo_init = batadv_softif_init_late, + .ndo_open = batadv_interface_open, + .ndo_stop = batadv_interface_release, + .ndo_get_stats = batadv_interface_stats, + .ndo_set_mac_address = batadv_interface_set_mac_addr, + .ndo_change_mtu = batadv_interface_change_mtu, + .ndo_start_xmit = batadv_interface_tx, + .ndo_validate_addr = eth_validate_addr +}; + +/** + * batadv_softif_init_early - early stage initialization of soft interface + * @dev: registered network device to modify + */ +static void batadv_softif_init_early(struct net_device *dev) +{ + struct batadv_priv *priv = netdev_priv(dev); + + ether_setup(dev); + + dev->netdev_ops = &batadv_netdev_ops; + dev->destructor = free_netdev; + dev->tx_queue_len = 0; + + /* can't call min_mtu, because the needed variables + * have not been initialized yet + */ + dev->mtu = ETH_DATA_LEN; + /* reserve more space in the skbuff for our header */ + dev->hard_header_len = BATADV_HEADER_LEN; + + /* generate random address */ + eth_hw_addr_random(dev); + + SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops); + + memset(priv, 0, sizeof(*priv)); +} + +struct net_device *batadv_softif_create(const char *name) +{ + struct net_device *soft_iface; + int ret; + + soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, + batadv_softif_init_early); + if (!soft_iface) + return NULL; + + ret = register_netdevice(soft_iface); + if (ret < 0) { + pr_err("Unable to register the batman interface '%s': %i\n", + name, ret); + free_netdev(soft_iface); + return NULL; + } + + return soft_iface; }
void batadv_softif_destroy(struct net_device *soft_iface)
From: Sven Eckelmann sven@narfation.org
The deinitialization of the soft-interface created in ndo_init/constructor should be done in the destructor and not directly before calling unregister_netdevice
Signed-off-by: Sven Eckelmann sven@narfation.org --- soft-interface.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/soft-interface.c b/soft-interface.c index c5cb0a7..e889bfb 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -417,7 +417,6 @@ static void batadv_softif_destroy_finish(struct work_struct *work) cleanup_work); soft_iface = bat_priv->soft_iface;
- batadv_debugfs_del_meshif(soft_iface); batadv_sysfs_del_meshif(soft_iface);
rtnl_lock(); @@ -522,6 +521,17 @@ static const struct net_device_ops batadv_netdev_ops = { };
/** + * batadv_softif_free - Deconstructor of batadv_soft_interface + * @dev: Device to cleanup and remove + */ +static void batadv_softif_free(struct net_device *dev) +{ + batadv_debugfs_del_meshif(dev); + batadv_mesh_free(dev); + free_netdev(dev); +} + +/** * batadv_softif_init_early - early stage initialization of soft interface * @dev: registered network device to modify */ @@ -532,7 +542,7 @@ static void batadv_softif_init_early(struct net_device *dev) ether_setup(dev);
dev->netdev_ops = &batadv_netdev_ops; - dev->destructor = free_netdev; + dev->destructor = batadv_softif_free; dev->tx_queue_len = 0;
/* can't call min_mtu, because the needed variables @@ -575,7 +585,6 @@ void batadv_softif_destroy(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface);
- batadv_mesh_free(soft_iface); queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); }
On Monday, February 11, 2013 17:10:23 Marek Lindner wrote:
From: Sven Eckelmann sven@narfation.org
The deinitialization of the soft-interface created in ndo_init/constructor should be done in the destructor and not directly before calling unregister_netdevice
Signed-off-by: Sven Eckelmann sven@narfation.org
soft-interface.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
Applied in revision ab8f433.
Thanks, Marek
From: Sven Eckelmann sven@narfation.org
batman-adv has an unusual way to manage softinterfaces. These will be created automatically when a user writes to the batman-adv/mesh_iface file in sysfs and removed when no slave device exists anymore.
This behaviour cannot be changed without breaking compatibility with existing code. Instead other interfaces should be able to slightly reduce this behaviour and provide a more common reaction to a removal of a slave interface.
Signed-off-by: Sven Eckelmann sven@narfation.org --- hard-interface.c | 8 +++++--- hard-interface.h | 13 ++++++++++++- sysfs.c | 6 ++++-- 3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index da000e9..74e3ec2 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -408,7 +408,8 @@ err: return ret; }
-void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface) +void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, + enum batadv_hard_if_cleanup autodel) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_hard_iface *primary_if = NULL; @@ -446,7 +447,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface) dev_put(hard_iface->soft_iface);
/* nobody uses this interface anymore */ - if (!bat_priv->num_ifaces) + if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO) batadv_softif_destroy(hard_iface->soft_iface);
hard_iface->soft_iface = NULL; @@ -533,7 +534,8 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
/* first deactivate interface */ if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) - batadv_hardif_disable_interface(hard_iface); + batadv_hardif_disable_interface(hard_iface, + BATADV_IF_CLEANUP_AUTO);
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) return; diff --git a/hard-interface.h b/hard-interface.h index 308437d..4989288 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -29,13 +29,24 @@ enum batadv_hard_if_state { BATADV_IF_I_WANT_YOU, };
+/** + * enum batadv_hard_if_cleanup - Cleanup modi for soft_iface after slave removal + * @BATADV_IF_CLEANUP_KEEP: Don't automatically delete soft-interface + * @BATADV_IF_CLEANUP_AUTO: Delete soft-interface after last slave was removed + */ +enum batadv_hard_if_cleanup { + BATADV_IF_CLEANUP_KEEP, + BATADV_IF_CLEANUP_AUTO, +}; + extern struct notifier_block batadv_hard_if_notifier;
struct batadv_hard_iface* batadv_hardif_get_by_netdev(const struct net_device *net_dev); int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, const char *iface_name); -void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface); +void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, + enum batadv_hard_if_cleanup autodel); void batadv_hardif_remove_interfaces(void); int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); diff --git a/sysfs.c b/sysfs.c index ce39f62..15a22ef 100644 --- a/sysfs.c +++ b/sysfs.c @@ -588,13 +588,15 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, }
if (status_tmp == BATADV_IF_NOT_IN_USE) { - batadv_hardif_disable_interface(hard_iface); + batadv_hardif_disable_interface(hard_iface, + BATADV_IF_CLEANUP_AUTO); goto unlock; }
/* if the interface already is in use */ if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) - batadv_hardif_disable_interface(hard_iface); + batadv_hardif_disable_interface(hard_iface, + BATADV_IF_CLEANUP_AUTO);
ret = batadv_hardif_enable_interface(hard_iface, buff);
On Monday, February 11, 2013 17:10:24 Marek Lindner wrote:
From: Sven Eckelmann sven@narfation.org
batman-adv has an unusual way to manage softinterfaces. These will be created automatically when a user writes to the batman-adv/mesh_iface file in sysfs and removed when no slave device exists anymore.
This behaviour cannot be changed without breaking compatibility with existing code. Instead other interfaces should be able to slightly reduce this behaviour and provide a more common reaction to a removal of a slave interface.
Signed-off-by: Sven Eckelmann sven@narfation.org
hard-interface.c | 8 +++++--- hard-interface.h | 13 ++++++++++++- sysfs.c | 6 ++++-- 3 files changed, 21 insertions(+), 6 deletions(-)
Applied in revision c3c7e74.
Thanks, Marek
Signed-off-by: Marek Lindner lindner_marek@yahoo.de CC: Sven Eckelmann sven@narfation.org --- hard-interface.c | 2 +- soft-interface.c | 6 +++++- soft-interface.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c index 74e3ec2..6c32607 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -448,7 +448,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
/* nobody uses this interface anymore */ if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO) - batadv_softif_destroy(hard_iface->soft_iface); + batadv_softif_destroy_sysfs(hard_iface->soft_iface);
hard_iface->soft_iface = NULL; batadv_hardif_free_ref(hard_iface); diff --git a/soft-interface.c b/soft-interface.c index e889bfb..bc77a5b 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -581,7 +581,11 @@ struct net_device *batadv_softif_create(const char *name) return soft_iface; }
-void batadv_softif_destroy(struct net_device *soft_iface) +/** + * batadv_softif_destroy_sysfs - deletion of batadv_soft_interface via sysfs + * @soft_iface: the to-be-removed batman-adv interface + */ +void batadv_softif_destroy_sysfs(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface);
diff --git a/soft-interface.h b/soft-interface.h index 43182e5..49bc66b 100644 --- a/soft-interface.h +++ b/soft-interface.h @@ -25,7 +25,7 @@ void batadv_interface_rx(struct net_device *soft_iface, struct sk_buff *skb, struct batadv_hard_iface *recv_if, int hdr_size, struct batadv_orig_node *orig_node); struct net_device *batadv_softif_create(const char *name); -void batadv_softif_destroy(struct net_device *soft_iface); +void batadv_softif_destroy_sysfs(struct net_device *soft_iface); int batadv_softif_is_valid(const struct net_device *net_dev);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
On Monday, February 11, 2013 17:10:25 Marek Lindner wrote:
Signed-off-by: Marek Lindner lindner_marek@yahoo.de CC: Sven Eckelmann sven@narfation.org
hard-interface.c | 2 +- soft-interface.c | 6 +++++- soft-interface.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-)
Applied in revision b047bd8.
Cheers, Marek
From: Sven Eckelmann sven@narfation.org
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 --- main.c | 2 ++ main.h | 1 + soft-interface.c | 29 +++++++++++++++++++++++++++++ soft-interface.h | 1 + 4 files changed, 33 insertions(+)
diff --git a/main.c b/main.c index bbb91a5..afccc3d 100644 --- a/main.c +++ b/main.c @@ -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();
diff --git a/main.h b/main.h index 8a9caa0..140f008 100644 --- a/main.h +++ b/main.h @@ -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 "compat.h" diff --git a/soft-interface.c b/soft-interface.c index bc77a5b..4ef1649 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -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 + */ +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) { diff --git a/soft-interface.h b/soft-interface.h index 49bc66b..2f2472c 100644 --- a/soft-interface.h +++ b/soft-interface.h @@ -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_ */
On Monday, February 11, 2013 17:10:26 Marek Lindner wrote:
From: Sven Eckelmann sven@narfation.org
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
main.c | 2 ++ main.h | 1 + soft-interface.c | 29 +++++++++++++++++++++++++++++ soft-interface.h | 1 + 4 files changed, 33 insertions(+)
Applied in revision 5317331.
Thanks, Marek
From: Sven Eckelmann sven@narfation.org
The sysfs configuration interface of batman-adv to add/remove slaves of an soft-iface is not deadlock free and doesn't follow the currently common way to modify slaves of an interface.
An additional configuration interface though rtnl_link is introduced which provides easy device adding/removing with tools like "ip": $ ip link set dev eth0 master bat0 $ ip link set dev eth0 nomaster
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat.h | 3 +++ hard-interface.c | 11 +++++++++-- soft-interface.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/compat.h b/compat.h index 48180e2..425b3d9 100644 --- a/compat.h +++ b/compat.h @@ -212,6 +212,9 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) \ }\ static int __batadv_interface_set_mac_addr(x, y)
+#define netdev_master_upper_dev_link netdev_set_master +#define netdev_upper_dev_unlink(slave, master) netdev_set_master(slave, NULL) + #endif /* < KERNEL_VERSION(3, 9, 0) */
#endif /* _NET_BATMAN_ADV_COMPAT_H_ */ diff --git a/hard-interface.c b/hard-interface.c index 6c32607..c08e39e 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -350,9 +350,13 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, hard_iface->soft_iface = soft_iface; bat_priv = netdev_priv(hard_iface->soft_iface);
+ ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface); + if (ret) + goto err_dev; + ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface); if (ret < 0) - goto err_dev; + goto err_upper;
hard_iface->if_num = bat_priv->num_ifaces; bat_priv->num_ifaces++; @@ -362,7 +366,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, bat_priv->bat_algo_ops->bat_iface_disable(hard_iface); bat_priv->num_ifaces--; hard_iface->if_status = BATADV_IF_NOT_IN_USE; - goto err_dev; + goto err_upper; }
hard_iface->batman_adv_ptype.type = ethertype; @@ -401,6 +405,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, out: return 0;
+err_upper: + netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface); err_dev: dev_put(soft_iface); err: @@ -450,6 +456,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO) batadv_softif_destroy_sysfs(hard_iface->soft_iface);
+ netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface); hard_iface->soft_iface = NULL; batadv_hardif_free_ref(hard_iface);
diff --git a/soft-interface.c b/soft-interface.c index 4ef1649..39caefa 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -509,6 +509,58 @@ free_bat_counters: return ret; }
+/** + * batadv_softif_slave_add - Add a slave interface to a batadv_soft_interface + * @dev: batadv_soft_interface used as master interface + * @slave_dev: net_device which should become the slave interface + * + * Return 0 if successful or error otherwise. + */ +static int batadv_softif_slave_add(struct net_device *dev, + struct net_device *slave_dev) +{ + struct batadv_hard_iface *hard_iface; + int ret = -EINVAL; + + hard_iface = batadv_hardif_get_by_netdev(slave_dev); + if (!hard_iface || hard_iface->soft_iface != NULL) + goto out; + + ret = batadv_hardif_enable_interface(hard_iface, dev->name); + +out: + if (hard_iface) + batadv_hardif_free_ref(hard_iface); + return ret; +} + +/** + * batadv_softif_slave_del - Delete a slave iface from a batadv_soft_interface + * @dev: batadv_soft_interface used as master interface + * @slave_dev: net_device which should be removed from the master interface + * + * Return 0 if successful or error otherwise. + */ +static int batadv_softif_slave_del(struct net_device *dev, + struct net_device *slave_dev) +{ + struct batadv_hard_iface *hard_iface; + int ret = -EINVAL; + + hard_iface = batadv_hardif_get_by_netdev(slave_dev); + + if (!hard_iface || hard_iface->soft_iface != dev) + goto out; + + batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_KEEP); + ret = 0; + +out: + if (hard_iface) + batadv_hardif_free_ref(hard_iface); + return ret; +} + static const struct net_device_ops batadv_netdev_ops = { .ndo_init = batadv_softif_init_late, .ndo_open = batadv_interface_open, @@ -517,7 +569,9 @@ static const struct net_device_ops batadv_netdev_ops = { .ndo_set_mac_address = batadv_interface_set_mac_addr, .ndo_change_mtu = batadv_interface_change_mtu, .ndo_start_xmit = batadv_interface_tx, - .ndo_validate_addr = eth_validate_addr + .ndo_validate_addr = eth_validate_addr, + .ndo_add_slave = batadv_softif_slave_add, + .ndo_del_slave = batadv_softif_slave_del, };
/**
On Monday, February 11, 2013 17:10:27 Marek Lindner wrote:
From: Sven Eckelmann sven@narfation.org
The sysfs configuration interface of batman-adv to add/remove slaves of an soft-iface is not deadlock free and doesn't follow the currently common way to modify slaves of an interface.
An additional configuration interface though rtnl_link is introduced which provides easy device adding/removing with tools like "ip": $ ip link set dev eth0 master bat0 $ ip link set dev eth0 nomaster
Signed-off-by: Sven Eckelmann sven@narfation.org
compat.h | 3 +++ hard-interface.c | 11 +++++++++-- soft-interface.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-)
Applied in revision edd0853.
Thanks, Marek
On Monday, February 11, 2013 17:10:22 Marek Lindner wrote:
From: Sven Eckelmann sven@narfation.org
The initialization of an net_device object should be done in the init/constructor function and not from the outside after the register_netdevice was done to avoid race conditions.
Signed-off-by: Sven Eckelmann sven@narfation.org
hard-interface.c | 5 ++ soft-interface.c | 169 ++++++++++++++++++++++++++---------------------------- 2 files changed, 86 insertions(+), 88 deletions(-)
Applied in revision 03522f0.
Thanks, Marek
On Mon, Feb 11, 2013 at 05:10:04 +0800, Marek Lindner wrote:
Hi,
here the third patch series to get the netlink interface creation into shape. Changes since v2:
- Reference counting bugfix in batadv_add_slave() & batadv_del_slave()
- Master settings & compat support
Kudos to Antonio for providing the compat support and debugging the interface to the bitter end!
But..has the patchset been rebased on top of the latest master? Git am is complaining and cannot apply the patches.
Cheers,
On Tuesday, February 12, 2013 04:14:28 Antonio Quartulli wrote:
Changes since v2:
- Reference counting bugfix in batadv_add_slave() & batadv_del_slave()
- Master settings & compat support
Kudos to Antonio for providing the compat support and debugging the interface to the bitter end!
But..has the patchset been rebased on top of the latest master? Git am is complaining and cannot apply the patches.
Yes, it is based on master. You can check here: http://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/marek/netlink_if
Cheers, Marek
On Mon, Feb 11, 2013 at 05:10:04PM +0800, Marek Lindner wrote:
Hi,
here the third patch series to get the netlink interface creation into shape. Changes since v2:
- Reference counting bugfix in batadv_add_slave() & batadv_del_slave()
- Master settings & compat support
Kudos to Antonio for providing the compat support and debugging the interface to the bitter end!
For the whole series:
Acked-by: Antonio Quartulli ordex@autistici.org
b.a.t.m.a.n@lists.open-mesh.org