Hi,
This patchset makes batman-adv network namespace aware. A soft interface can be creates in a namespace and hard interfaces added to it. soft interfaces cannot be moved between name spaces.
The biggest change is to debugfs, which is not natively netns aware, unlike sysfs which is. A new netns directory has been added and within that, a directory per network name space which batman is used within. The changes are backwards compatible, in that interfaces in the global namespace are not placed into a subdirectory.
v3:
- Added new system to add patches to the build (in case the build against an older kernel is not possible otherwise) - Rearranged the retrieval of the link netns - Rearranged the retrieval netns id for debugfs - Fix header includes - Add compat-include for linux/ns_common.h - Add compat-patch for netdev->rtnl_link_ops->get_link_net - Add compat-patch for net->ns.inum - Fix alignment errors
Kind regards, Sven
compat-includes/compat.h can usually be used to solve compatibility problems with older kernels. This works well for functions, defines/enums and sometimes even structures that were introduced.
But this can fail when structs changed. Some of these can be solved in crude ways but sometimes it is unavoidable to have a version specific code. Unfortunately, this kind of code is not acceptable in the kernel and thus the compat infrastructure of the external module has to do add it automatically before the source is compiled.
This process works by creating a build directory which is prefilled with the source from net/batman-adv/. The patches from compat-patches/ will be applied on top of this copy and then the code is compiled.
Signed-off-by: Sven Eckelmann sven@narfation.org --- .gitignore | 7 +------ Makefile | 31 +++++++++++++++++++++++++++---- compat-patches/README | 23 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 compat-patches/README
diff --git a/.gitignore b/.gitignore index 59c6a30..1a8dbc0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ /compat-autoconf.h /compat-autoconf.h.tmp -/net/batman-adv/.* -/net/batman-adv/batman-adv.ko -/net/batman-adv/batman-adv.mod.c -/net/batman-adv/modules.order -/net/batman-adv/Module.symvers -/net/batman-adv/*.o +/build/ diff --git a/Makefile b/Makefile index 5d2c058..dc45cc8 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ export CONFIG_BATMAN_ADV_MCAST=y export CONFIG_BATMAN_ADV_BATMAN_V=n
PWD:=$(shell pwd) +BUILD_DIR=$(PWD)/build KERNELPATH ?= /lib/modules/$(shell uname -r)/build # sanity check: does KERNELPATH exist? ifeq ($(shell cd $(KERNELPATH) && pwd),) @@ -39,6 +40,14 @@ endif
export KERNELPATH RM ?= rm -f +MKDIR := mkdir -p +PATCH_FLAGS = --batch --fuzz=0 --forward --strip=1 --unified --version-control=never -g0 --remove-empty-files --no-backup-if-mismatch --reject-file=- +PATCH := patch $(PATCH_FLAGS) -i +CP := cp -fpR + +SOURCE = $(wildcard net/batman-adv/*.[ch]) net/batman-adv/Makefile +SOURCE_BUILD = $(wildcard $(BUILD_DIR)/net/batman-adv/*.[ch]) $(BUILD_DIR)/net/batman-adv/Makefile +SOURCE_STAMP = $(BUILD_DIR)/net/batman-adv/.compat-prepared
REVISION= $(shell if [ -d "$(PWD)/.git" ]; then \ echo $$(git --git-dir="$(PWD)/.git" describe --always --dirty --match "v*" |sed 's/^v//' 2> /dev/null || echo "[unknown]"); \ @@ -53,7 +62,7 @@ NOSTDINC_FLAGS += -DBATADV_SOURCE_VERSION="$(REVISION)" endif
BUILD_FLAGS := \ - M=$(PWD)/net/batman-adv \ + M=$(BUILD_DIR)/net/batman-adv \ CONFIG_BATMAN_ADV=m \ CONFIG_BATMAN_ADV_DEBUG=$(CONFIG_BATMAN_ADV_DEBUG) \ CONFIG_BATMAN_ADV_BLA=$(CONFIG_BATMAN_ADV_BLA) \ @@ -63,18 +72,32 @@ BUILD_FLAGS := \ CONFIG_BATMAN_ADV_BATMAN_V=$(CONFIG_BATMAN_ADV_BATMAN_V) \ INSTALL_MOD_DIR=updates/net/batman-adv/
-all: config +all: config $(SOURCE_STAMP) $(MAKE) -C $(KERNELPATH) $(BUILD_FLAGS) modules
clean: $(RM) compat-autoconf.h* - $(MAKE) -C $(KERNELPATH) $(BUILD_FLAGS) clean + $(RM) -r $(BUILD_DIR)
-install: config +install: config $(SOURCE_STAMP) $(MAKE) -C $(KERNELPATH) $(BUILD_FLAGS) modules_install depmod -a
config: $(PWD)/gen-compat-autoconf.sh $(PWD)/compat-autoconf.h
+$(SOURCE_STAMP): $(SOURCE) compat-patches/* + $(MKDIR) $(BUILD_DIR)/net/batman-adv/ + @$(RM) $(SOURCE_BUILD) + @$(CP) $(SOURCE) $(BUILD_DIR)/net/batman-adv/ + @set -e; \ + patches="$$(ls -1 compat-patches/|grep '.patch$$'|sort)"; \ + for i in $${patches}; do \ + echo ' COMPAT_PATCH '$${i};\ + cd $(BUILD_DIR); \ + $(PATCH) ../compat-patches/$${i}; \ + cd - > /dev/null; \ + done + touch $(SOURCE_STAMP) + .PHONY: all clean install config diff --git a/compat-patches/README b/compat-patches/README new file mode 100644 index 0000000..3bbddb3 --- /dev/null +++ b/compat-patches/README @@ -0,0 +1,23 @@ +WARNING +======= + +Please avoid using the compat-patches/ to implement support for old kernels. +This should be the last resort. + + * it is nearly always possible to use compat-includes/ to do the same with a + lot less problems + + * maintaining these patches is *censored* + +GENERATING A PATCH +================== + +If it not possible to avoid a patch then please make the patch as small as +possible. Even refactor the code which has to be patched to reduce the +size/number of the changes. + +Please use git-format-patches to generate them and order same inside via the +XXXX- prefix of the patch name. + + git format-patch --abbrev=7 -U3 --diff-algorithm=histogram --no-signature \ + --format=format:'From: %an <%ae>%nDate: %aD%nSubject: [PATCH] %B' -1
From: Andrew Lunn andrew@lunn.ch
The batX soft interface should not be moved between network name spaces. This is similar to bridges, bonds, tunnels, which are not allowed to move between network namespaces.
Suggested-by: Daniel Ehlers danielehlers@mindeye.net Signed-off-by: Andrew Lunn andrew@lunn.ch Acked-by: Antonio Quartulli a@unstable.cc Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/soft-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 7679f3a..f4aa60a 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -955,7 +955,7 @@ static void batadv_softif_init_early(struct net_device *dev)
dev->netdev_ops = &batadv_netdev_ops; dev->destructor = batadv_softif_free; - dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL; dev->priv_flags |= IFF_NO_QUEUE;
/* can't call min_mtu, because the needed variables
From: Andrew Lunn andrew@lunn.ch
When creating a soft interface, create it in the same netns as the hard interface. Replace all references to init_net with the correct name space for the interface being manipulated.
Suggested-by: Daniel Ehlers danielehlers@mindeye.net Signed-off-by: Andrew Lunn andrew@lunn.ch Acked-by: Antonio Quartulli a@unstable.cc Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/hard-interface.c | 10 +++++----- net/batman-adv/hard-interface.h | 3 ++- net/batman-adv/soft-interface.c | 7 +++++-- net/batman-adv/soft-interface.h | 3 ++- net/batman-adv/sysfs.c | 3 ++- net/batman-adv/translation-table.c | 4 ++-- 6 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 3240a67..ca8e0d4 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -36,7 +36,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <net/net_namespace.h>
#include "bridge_loop_avoidance.h" #include "debugfs.h" @@ -121,6 +120,7 @@ static bool batadv_mutual_parents(const struct net_device *dev1, static bool batadv_is_on_batman_iface(const struct net_device *net_dev) { struct net_device *parent_dev; + struct net *net = dev_net(net_dev); bool ret;
/* check if this is a batman-adv mesh interface */ @@ -133,7 +133,7 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) return false;
/* recurse over the parent device */ - parent_dev = __dev_get_by_index(&init_net, dev_get_iflink(net_dev)); + parent_dev = __dev_get_by_index(net, dev_get_iflink(net_dev)); /* if we got a NULL parent_dev there is something broken.. */ if (WARN(!parent_dev, "Cannot find parent device")) return false; @@ -453,7 +453,7 @@ static int batadv_master_del_slave(struct batadv_hard_iface *slave, }
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, - const char *iface_name) + struct net *net, const char *iface_name) { struct batadv_priv *bat_priv; struct net_device *soft_iface, *master; @@ -467,10 +467,10 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, if (!kref_get_unless_zero(&hard_iface->refcount)) goto out;
- soft_iface = dev_get_by_name(&init_net, iface_name); + soft_iface = dev_get_by_name(net, iface_name);
if (!soft_iface) { - soft_iface = batadv_softif_create(iface_name); + soft_iface = batadv_softif_create(net, iface_name);
if (!soft_iface) { ret = -ENOMEM; diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index d74f198..a76724d 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -28,6 +28,7 @@ #include <linux/types.h>
struct net_device; +struct net;
enum batadv_hard_if_state { BATADV_IF_NOT_IN_USE, @@ -55,7 +56,7 @@ bool batadv_is_wifi_iface(int ifindex); 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); + struct net *net, const char *iface_name); void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, enum batadv_hard_if_cleanup autodel); void batadv_hardif_remove_interfaces(void); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index f4aa60a..14cf689 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -868,13 +868,14 @@ static int batadv_softif_slave_add(struct net_device *dev, struct net_device *slave_dev) { struct batadv_hard_iface *hard_iface; + struct net *net = dev_net(dev); int ret = -EINVAL;
hard_iface = batadv_hardif_get_by_netdev(slave_dev); if (!hard_iface || hard_iface->soft_iface) goto out;
- ret = batadv_hardif_enable_interface(hard_iface, dev->name); + ret = batadv_hardif_enable_interface(hard_iface, net, dev->name);
out: if (hard_iface) @@ -971,7 +972,7 @@ static void batadv_softif_init_early(struct net_device *dev) memset(priv, 0, sizeof(*priv)); }
-struct net_device *batadv_softif_create(const char *name) +struct net_device *batadv_softif_create(struct net *net, const char *name) { struct net_device *soft_iface; int ret; @@ -981,6 +982,8 @@ struct net_device *batadv_softif_create(const char *name) if (!soft_iface) return NULL;
+ dev_net_set(soft_iface, net); + soft_iface->rtnl_link_ops = &batadv_link_ops;
ret = register_netdevice(soft_iface); diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 0c5ab40..91b2b61 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -24,13 +24,14 @@ #include <net/rtnetlink.h>
struct net_device; +struct net; struct sk_buff;
int batadv_skb_head_push(struct sk_buff *skb, unsigned int len); 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); +struct net_device *batadv_softif_create(struct net *net, const char *name); void batadv_softif_destroy_sysfs(struct net_device *soft_iface); bool batadv_softif_is_valid(const struct net_device *net_dev); extern struct rtnl_link_ops batadv_link_ops; diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index e7cf513..6b1e54f 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -830,6 +830,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, size_t count) { struct net_device *net_dev = batadv_kobj_to_netdev(kobj); + struct net *net = dev_net(net_dev); struct batadv_hard_iface *hard_iface; int status_tmp = -1; int ret = count; @@ -873,7 +874,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_AUTO);
- ret = batadv_hardif_enable_interface(hard_iface, buff); + ret = batadv_hardif_enable_interface(hard_iface, net, buff);
unlock: rtnl_unlock(); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 2ed55f4..ce63a51 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -43,7 +43,6 @@ #include <linux/stddef.h> #include <linux/string.h> #include <linux/workqueue.h> -#include <net/net_namespace.h>
#include "bridge_loop_avoidance.h" #include "hard-interface.h" @@ -583,6 +582,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_tt_local_entry *tt_local; struct batadv_tt_global_entry *tt_global = NULL; + struct net *net = dev_net(soft_iface); struct batadv_softif_vlan *vlan; struct net_device *in_dev = NULL; struct hlist_head *head; @@ -594,7 +594,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, u32 match_mark;
if (ifindex != BATADV_NULL_IFINDEX) - in_dev = dev_get_by_index(&init_net, ifindex); + in_dev = dev_get_by_index(net, ifindex);
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
From: Andrew Lunn andrew@lunn.ch
batman-adv tries to prevent the user from placing a batX soft interface into another batman mesh as a hard interface. It does this by walking up the devices list of parents and ensures they are all none batX interfaces. iflink can point to an interface in a different namespace, so also retrieve the parents name space when finding the parent and use it when doing the comparison.
Signed-off-by: Andrew Lunn andrew@lunn.ch Acked-by: Antonio Quartulli a@untable.cc Signed-off-by: Sven Eckelmann sven@narfation.org --- compat-patches/0001-get_link_net.patch | 26 ++++++++++++++++++ net/batman-adv/hard-interface.c | 49 +++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 compat-patches/0001-get_link_net.patch
diff --git a/compat-patches/0001-get_link_net.patch b/compat-patches/0001-get_link_net.patch new file mode 100644 index 0000000..25ee879 --- /dev/null +++ b/compat-patches/0001-get_link_net.patch @@ -0,0 +1,26 @@ +From: Sven Eckelmann sven@narfation.org +Date: Sat, 12 Mar 2016 00:01:45 +0100 +Subject: [PATCH] get_link_net +--- + net/batman-adv/hard-interface.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index bd98195..f568053 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -97,10 +97,14 @@ static struct net *batadv_getlink_net(const struct net_device *netdev, + if (!netdev->rtnl_link_ops) + return fallback_net; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) ++ return fallback_net; ++#else + if (!netdev->rtnl_link_ops->get_link_net) + return fallback_net; + + return netdev->rtnl_link_ops->get_link_net(netdev); ++#endif + } + + /** diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index ca8e0d4..bd98195 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -36,6 +36,8 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> +#include <net/net_namespace.h> +#include <net/rtnetlink.h>
#include "bridge_loop_avoidance.h" #include "debugfs.h" @@ -83,25 +85,55 @@ out: }
/** + * batadv_getlink_net - return link net namespace (of use fallback) + * @netdev: net_device to check + * @fallback_net: return in case get_link_net is not available for @netdev + * + * Return: result of rtnl_link_ops->get_link_net or @fallback_net + */ +static struct net *batadv_getlink_net(const struct net_device *netdev, + struct net *fallback_net) +{ + if (!netdev->rtnl_link_ops) + return fallback_net; + + if (!netdev->rtnl_link_ops->get_link_net) + return fallback_net; + + return netdev->rtnl_link_ops->get_link_net(netdev); +} + +/** * batadv_mutual_parents - check if two devices are each others parent - * @dev1: 1st net_device - * @dev2: 2nd net_device + * @dev1: 1st net dev + * @net1: 1st devices netns + * @dev2: 2nd net dev + * @net2: 2nd devices netns * * veth devices come in pairs and each is the parent of the other! * * Return: true if the devices are each others parent, otherwise false */ static bool batadv_mutual_parents(const struct net_device *dev1, - const struct net_device *dev2) + struct net *net1, + const struct net_device *dev2, + struct net *net2) { int dev1_parent_iflink = dev_get_iflink(dev1); int dev2_parent_iflink = dev_get_iflink(dev2); + const struct net *dev1_parent_net; + const struct net *dev2_parent_net; + + dev1_parent_net = batadv_getlink_net(dev1, net1); + dev2_parent_net = batadv_getlink_net(dev2, net2);
if (!dev1_parent_iflink || !dev2_parent_iflink) return false;
return (dev1_parent_iflink == dev2->ifindex) && - (dev2_parent_iflink == dev1->ifindex); + (dev2_parent_iflink == dev1->ifindex) && + net_eq(dev1_parent_net, net2) && + net_eq(dev2_parent_net, net1); }
/** @@ -119,8 +151,9 @@ static bool batadv_mutual_parents(const struct net_device *dev1, */ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) { - struct net_device *parent_dev; struct net *net = dev_net(net_dev); + struct net_device *parent_dev; + struct net *parent_net; bool ret;
/* check if this is a batman-adv mesh interface */ @@ -132,13 +165,15 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) dev_get_iflink(net_dev) == net_dev->ifindex) return false;
+ parent_net = batadv_getlink_net(net_dev, net); + /* recurse over the parent device */ - parent_dev = __dev_get_by_index(net, dev_get_iflink(net_dev)); + parent_dev = __dev_get_by_index(parent_net, dev_get_iflink(net_dev)); /* if we got a NULL parent_dev there is something broken.. */ if (WARN(!parent_dev, "Cannot find parent device")) return false;
- if (batadv_mutual_parents(net_dev, parent_dev)) + if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) return false;
ret = batadv_is_on_batman_iface(parent_dev);
linux/ns_common.h was added with 3.19. All older kernels should not include this header to avoid compile errors.
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat-include/linux/ns_common.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 compat-include/linux/ns_common.h
diff --git a/compat-include/linux/ns_common.h b/compat-include/linux/ns_common.h new file mode 100644 index 0000000..a60a77f --- /dev/null +++ b/compat-include/linux/ns_common.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 B.A.T.M.A.N. contributors: + * + * Marek Lindner, Simon Wunderlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/. + * + * This file contains macros for maintaining compatibility with older versions + * of the Linux kernel. + */ + +#ifndef _NET_BATMAN_ADV_COMPAT_LINUX_NS_COMMON_H_ +#define _NET_BATMAN_ADV_COMPAT_LINUX_NS_COMMON_H_ + +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) +#include_next <linux/ns_common.h> +#endif /* >= KERNEL_VERSION(3, 19, 0) */ + +#endif /* _NET_BATMAN_ADV_COMPAT_LINUX_NS_COMMON_H_ */
From: Andrew Lunn andrew@lunn.ch
Unlike sysfs, debugfs is not netns aware. So batman has to take care to avoid namespace clashes.
Each namespace is given a directory within debugfs/batman-adv/netns, using the namespaces inum as the directory name.
Files for namespaces other than the global namespace are placed within the namespace specific directory. Additionally, a symbolic link is used to link the global namespaces inum back to debugfs/batman-adv/ so tools do not need to differentiate between the global namespace and other namespaces.
Signed-off-by: Andrew Lunn andrew@lunn.ch Signed-off-by: Sven Eckelmann sven@narfation.org --- compat-patches/0002-ns.inum.patch | 25 ++++++++ net/batman-adv/debugfs.c | 130 +++++++++++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 compat-patches/0002-ns.inum.patch
diff --git a/compat-patches/0002-ns.inum.patch b/compat-patches/0002-ns.inum.patch new file mode 100644 index 0000000..9856f6e --- /dev/null +++ b/compat-patches/0002-ns.inum.patch @@ -0,0 +1,25 @@ +From: Sven Eckelmann sven@narfation.org +Date: Sat, 12 Mar 2016 00:24:58 +0100 +Subject: [PATCH] ns.inum +--- + net/batman-adv/debugfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c +index cc583e6..59616a6 100644 +--- a/net/batman-adv/debugfs.c ++++ b/net/batman-adv/debugfs.c +@@ -78,7 +78,13 @@ static DEFINE_MUTEX(batadv_debugfs_ns_mutex); + */ + static unsigned int batadv_debugfs_ns_id(const struct net *net) + { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) ++ return 0; /* ???? */ ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) ++ return net->proc_inum; ++#else + return net->ns.inum; ++#endif + } + + static struct dentry *batadv_debugfs_ns_get(struct net *net) diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 3dc5208..cc583e6 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c @@ -27,8 +27,12 @@ #include <linux/fs.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> +#include <linux/list.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/netdevice.h> +#include <linux/ns_common.h> #include <linux/poll.h> #include <linux/printk.h> #include <linux/sched.h> /* for linux/wait.h */ @@ -42,6 +46,7 @@ #include <linux/types.h> #include <linux/uaccess.h> #include <linux/wait.h> +#include <net/net_namespace.h> #include <stdarg.h>
#include "bridge_loop_avoidance.h" @@ -53,6 +58,84 @@ #include "translation-table.h"
static struct dentry *batadv_debugfs; +static struct dentry *batadv_ns_debugfs; + +struct batadv_debugfs_ns_entry { + struct net *net; + struct dentry *dir; + struct kref refcount; + struct list_head link; +}; + +static LIST_HEAD(batadv_debugfs_ns); +static DEFINE_MUTEX(batadv_debugfs_ns_mutex); + +/** + * batadv_debugfs_ns_id - Get namespace specific id + * @net: namespace of the soft-interface + * + * Return: internal id of the namespace + */ +static unsigned int batadv_debugfs_ns_id(const struct net *net) +{ + return net->ns.inum; +} + +static struct dentry *batadv_debugfs_ns_get(struct net *net) +{ + struct batadv_debugfs_ns_entry *ns_entry; + char name[32]; + + mutex_lock(&batadv_debugfs_ns_mutex); + list_for_each_entry(ns_entry, &batadv_debugfs_ns, link) { + if (ns_entry->net == net) { + kref_get(&ns_entry->refcount); + mutex_unlock(&batadv_debugfs_ns_mutex); + return ns_entry->dir; + } + } + + ns_entry = kzalloc(sizeof(*ns_entry), GFP_ATOMIC); + if (ns_entry) { + INIT_LIST_HEAD(&ns_entry->link); + ns_entry->net = net; + kref_init(&ns_entry->refcount); + sprintf(name, "%u", batadv_debugfs_ns_id(net)); + ns_entry->dir = debugfs_create_dir(name, batadv_ns_debugfs); + if (!ns_entry->dir) { + kfree(ns_entry); + mutex_unlock(&batadv_debugfs_ns_mutex); + return NULL; + } + list_add(&ns_entry->link, &batadv_debugfs_ns); + } + mutex_unlock(&batadv_debugfs_ns_mutex); + return ns_entry->dir; +} + +static void batadv_ns_entry_release(struct kref *ref) +{ + struct batadv_debugfs_ns_entry *ns_entry; + + ns_entry = container_of(ref, struct batadv_debugfs_ns_entry, refcount); + debugfs_remove_recursive(ns_entry->dir); + list_del(&ns_entry->link); + kfree(ns_entry); +} + +static void batadv_debugfs_ns_put(struct net *net) +{ + struct batadv_debugfs_ns_entry *ns_entry; + + mutex_lock(&batadv_debugfs_ns_mutex); + list_for_each_entry(ns_entry, &batadv_debugfs_ns, link) { + if (ns_entry->net == net) { + kref_put(&ns_entry->refcount, batadv_ns_entry_release); + break; + } + } + mutex_unlock(&batadv_debugfs_ns_mutex); +}
#ifdef CONFIG_BATMAN_ADV_DEBUG #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) @@ -451,6 +534,7 @@ void batadv_debugfs_init(void) { struct batadv_debuginfo **bat_debug; struct dentry *file; + char name[32];
batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL); if (batadv_debugfs == ERR_PTR(-ENODEV)) @@ -471,6 +555,15 @@ void batadv_debugfs_init(void) } }
+ batadv_ns_debugfs = debugfs_create_dir("netns", batadv_debugfs); + if (!batadv_ns_debugfs) + goto err; + + /* Create a symlink for the default name space */ + sprintf(name, "%u", batadv_debugfs_ns_id(&init_net)); + if (!debugfs_create_symlink(name, batadv_ns_debugfs, "..")) + goto err; + return; err: debugfs_remove_recursive(batadv_debugfs); @@ -492,14 +585,24 @@ void batadv_debugfs_destroy(void) */ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) { + struct net *net = dev_net(hard_iface->net_dev); + char *name = hard_iface->net_dev->name; struct batadv_debuginfo **bat_debug; + struct dentry *debugfs_ns_dir; struct dentry *file;
if (!batadv_debugfs) goto out;
- hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name, - batadv_debugfs); + debugfs_ns_dir = batadv_debugfs; + + if (net != &init_net) { + debugfs_ns_dir = batadv_debugfs_ns_get(net); + if (!debugfs_ns_dir) + goto out; + } + + hard_iface->debug_dir = debugfs_create_dir(name, debugfs_ns_dir); if (!hard_iface->debug_dir) goto out;
@@ -517,6 +620,8 @@ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) rem_attr: debugfs_remove_recursive(hard_iface->debug_dir); hard_iface->debug_dir = NULL; + if (net != &init_net) + batadv_debugfs_ns_put(net); out: return -ENOMEM; } @@ -528,22 +633,36 @@ out: */ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface) { + struct net *net = dev_net(hard_iface->net_dev); + if (batadv_debugfs) { debugfs_remove_recursive(hard_iface->debug_dir); hard_iface->debug_dir = NULL; } + if (net != &init_net) + batadv_debugfs_ns_put(net); }
int batadv_debugfs_add_meshif(struct net_device *dev) { struct batadv_priv *bat_priv = netdev_priv(dev); struct batadv_debuginfo **bat_debug; + struct net *net = dev_net(dev); + struct dentry *debugfs_ns_dir; struct dentry *file;
if (!batadv_debugfs) goto out;
- bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs); + debugfs_ns_dir = batadv_debugfs; + + if (net != &init_net) { + debugfs_ns_dir = batadv_debugfs_ns_get(net); + if (!debugfs_ns_dir) + goto out; + } + + bat_priv->debug_dir = debugfs_create_dir(dev->name, debugfs_ns_dir); if (!bat_priv->debug_dir) goto out;
@@ -572,6 +691,8 @@ int batadv_debugfs_add_meshif(struct net_device *dev) rem_attr: debugfs_remove_recursive(bat_priv->debug_dir); bat_priv->debug_dir = NULL; + if (net != &init_net) + batadv_debugfs_ns_put(net); out: return -ENOMEM; } @@ -579,6 +700,7 @@ out: void batadv_debugfs_del_meshif(struct net_device *dev) { struct batadv_priv *bat_priv = netdev_priv(dev); + struct net *net = dev_net(dev);
batadv_debug_log_cleanup(bat_priv);
@@ -586,4 +708,6 @@ void batadv_debugfs_del_meshif(struct net_device *dev) debugfs_remove_recursive(bat_priv->debug_dir); bat_priv->debug_dir = NULL; } + if (net != &init_net) + batadv_debugfs_ns_put(net); }
On Sunday 13 March 2016 19:50:34 Sven Eckelmann wrote:
From: Andrew Lunn andrew@lunn.ch
Unlike sysfs, debugfs is not netns aware. So batman has to take care to avoid namespace clashes.
Each namespace is given a directory within debugfs/batman-adv/netns, using the namespaces inum as the directory name.
Files for namespaces other than the global namespace are placed within the namespace specific directory. Additionally, a symbolic link is used to link the global namespaces inum back to debugfs/batman-adv/ so tools do not need to differentiate between the global namespace and other namespaces.
Signed-off-by: Andrew Lunn andrew@lunn.ch Signed-off-by: Sven Eckelmann sven@narfation.org
compat-patches/0002-ns.inum.patch | 25 ++++++++ net/batman-adv/debugfs.c | 130 +++++++++++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 compat-patches/0002-ns.inum.patch
Matthias is against applying [1] patch 6 because it would require that batman-adv supports this interface for a long(tm) time. He proposes to use netlink instead.
Andrew, do you want to change patch 6 to avoid creating the debugfs stuff in non-init_net netns?
Kind regards, Sven
[1] https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2016-March/014690.html
Matthias is against applying [1] patch 6 because it would require that batman-adv supports this interface for a long(tm) time. He proposes to use netlink instead.
Andrew, do you want to change patch 6 to avoid creating the debugfs stuff in non-init_net netns?
I'm not sure how well that is going to work, from the user space side of things.
In the kernel, we know if we are in init_net, or some other netns.
In user space, it is not so simple. Ideally, when in some other netns than the default, we need all reads/writes to debugfs to fail. What we don't want is it seeing the default name spaces files, because it is going to get very confusing. These files refer to something which does not exist in the current netns.
The problem is, how do we find out if we are in a different netns than default?
Andrew
On Monday 14 March 2016 15:06:24 Andrew Lunn wrote:
Matthias is against applying [1] patch 6 because it would require that batman-adv supports this interface for a long(tm) time. He proposes to use netlink instead.
Andrew, do you want to change patch 6 to avoid creating the debugfs stuff in non-init_net netns?
I'm not sure how well that is going to work, from the user space side of things.
In the kernel, we know if we are in init_net, or some other netns.
In user space, it is not so simple. Ideally, when in some other netns than the default, we need all reads/writes to debugfs to fail.
Hm, this would require some checks via the the current pid on open:
net = get_net_ns_by_pid(current->pid); ... checky check via neteq(net, &init_net)... put_net(pd->net);
What we don't want is it seeing the default name spaces files, because it is going to get very confusing. These files refer to something which does not exist in the current netns.
Wait, but thats exactly what you are doing already with your default behavior (which only creates a symlink to netns/${FUNNY_ID}/. Legacy tools will still read the wrong information because they don't know about the new netns paths.
I thought that the debugfs stuff will be replaced with netlink and that the current debugfs files are only there for non-namespace setups with legacy tools.
Kind regards, Sven
On Mon, Mar 14, 2016 at 04:56:57PM +0100, Sven Eckelmann wrote:
On Monday 14 March 2016 15:06:24 Andrew Lunn wrote:
Matthias is against applying [1] patch 6 because it would require that batman-adv supports this interface for a long(tm) time. He proposes to use netlink instead.
Andrew, do you want to change patch 6 to avoid creating the debugfs stuff in non-init_net netns?
I'm not sure how well that is going to work, from the user space side of things.
In the kernel, we know if we are in init_net, or some other netns.
In user space, it is not so simple. Ideally, when in some other netns than the default, we need all reads/writes to debugfs to fail.
Hm, this would require some checks via the the current pid on open:
net = get_net_ns_by_pid(current->pid); ... checky check via neteq(net, &init_net)... put_net(pd->net);
I suppose this could be made to work. Not sure what error code to return, maybe ENXIO if batctl is not in the default netns.
What we don't want is it seeing the default name spaces files, because it is going to get very confusing. These files refer to something which does not exist in the current netns.
Wait, but thats exactly what you are doing already with your default behavior (which only creates a symlink to netns/${FUNNY_ID}/. Legacy tools will still read the wrong information because they don't know about the new netns paths.
Correct. And this is unfixable, as far as i can see. You need the contents of debugfs to be dependent on the observer. The requires core debugfs support to calls like readdir() and open().
I thought that the debugfs stuff will be replaced with netlink and that the current debugfs files are only there for non-namespace setups with legacy tools.
Legacy tools are always going to be broken when they are used in the non-default netns. Probably the best we can do is have the kernel return ENXIO or whatever when they access files from a different netns.
We have two options for non-default netns debugfs
1) Extend debugfs and the tools as i suggested patches for.
2) Only support default netns in debugfs, and use netlink for full netns aware tools.
Andrew
v3:
- Added new system to add patches to the build (in case the build against an older kernel is not possible otherwise)
- Rearranged the retrieval of the link netns
- Rearranged the retrieval netns id for debugfs
- Fix header includes
- Add compat-include for linux/ns_common.h
- Add compat-patch for netdev->rtnl_link_ops->get_link_net
- Add compat-patch for net->ns.inum
- Fix alignment errors
Hi Sven
This all looks good. Thanks.
Which old kernels does this support? Has it forced some old ones to be dropped from the supported list?
Andrew
On Sunday 13 March 2016 23:40:47 Andrew Lunn wrote:
v3:
- Added new system to add patches to the build (in case the build against
an> older kernel is not possible otherwise)
- Rearranged the retrieval of the link netns
- Rearranged the retrieval netns id for debugfs
- Fix header includes
- Add compat-include for linux/ns_common.h
- Add compat-patch for netdev->rtnl_link_ops->get_link_net
- Add compat-patch for net->ns.inum
- Fix alignment errors
Hi Sven
This all looks good. Thanks.
Which old kernels does this support? Has it forced some old ones to be dropped from the supported list?
I have only tested to build against kernel 3.2-4.4. But it should still support 2.6.29 (untested).
Kind regards, Sven
b.a.t.m.a.n@lists.open-mesh.org