This patchset completes netns support, by disabling debugfs entries when not in the default name space, and correctly handling interface stack loops when the parent is in a different name space.
It additionally adds netlink support for most of the information found in debugfs, and is netns awaire.
Note: BLA is untested, so best assume it is broken...
batctl patches to follow.
Andrew Lunn (5): batman-adv: Handle parent interfaces in a different netns batman-adv: Suppress debugfs entries for netns's batman-adv: Indicate netlink socket can be used with netns. batman-adv: add B.A.T.M.A.N. Dump gateways via netlink batman-adv: add B.A.T.M.A.N. Dump BLA claims via netlink
Matthias Schiffer (5): batman-adv: add generic netlink query API to replace debugfs files batman-adv: netlink: add translation table query batman-adv: netlink: add originator and neighbor table queries batman-adv: add B.A.T.M.A.N. IV bat_{orig, neigh}_dump implementations batman-adv: add B.A.T.M.A.N. V bat_{orig, neigh}_dump implementations
Makefile | 1 + include/uapi/linux/batman_adv.h | 111 ++++++++++++ net/batman-adv/Makefile | 1 + net/batman-adv/bat_iv_ogm.c | 268 +++++++++++++++++++++++++++++ net/batman-adv/bat_v.c | 250 +++++++++++++++++++++++++++ net/batman-adv/bridge_loop_avoidance.c | 162 +++++++++++++++++ net/batman-adv/bridge_loop_avoidance.h | 9 +- net/batman-adv/debugfs.c | 19 +- net/batman-adv/gateway_client.c | 126 ++++++++++++++ net/batman-adv/gateway_client.h | 1 + net/batman-adv/hard-interface.c | 31 +++- net/batman-adv/main.c | 48 ++++++ net/batman-adv/main.h | 1 + net/batman-adv/netlink.c | 291 +++++++++++++++++++++++++++++++ net/batman-adv/netlink.h | 36 ++++ net/batman-adv/originator.c | 142 +++++++++++++++ net/batman-adv/originator.h | 2 + net/batman-adv/packet.h | 36 ---- net/batman-adv/translation-table.c | 305 +++++++++++++++++++++++++++++++++ net/batman-adv/translation-table.h | 2 + net/batman-adv/types.h | 7 + 21 files changed, 1804 insertions(+), 45 deletions(-) create mode 100644 include/uapi/linux/batman_adv.h create mode 100644 net/batman-adv/netlink.c create mode 100644 net/batman-adv/netlink.h
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 --- net/batman-adv/hard-interface.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 8c2f399..e0cd7ce 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -84,24 +84,37 @@ out:
/** * 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) + const struct net *net1, + const struct net_device *dev2, + const 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 = net1; + const struct net *dev2_parent_net = net2; + + if (dev1->rtnl_link_ops && dev1->rtnl_link_ops->get_link_net) + dev1_parent_net = dev1->rtnl_link_ops->get_link_net(dev1); + if (dev2->rtnl_link_ops && dev2->rtnl_link_ops->get_link_net) + dev2_parent_net = dev2->rtnl_link_ops->get_link_net(dev2);
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 +132,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 = net; bool ret;
/* check if this is a batman-adv mesh interface */ @@ -132,13 +146,16 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) dev_get_iflink(net_dev) == net_dev->ifindex) return false;
+ if (net_dev->rtnl_link_ops && net_dev->rtnl_link_ops->get_link_net) + parent_net = net_dev->rtnl_link_ops->get_link_net(net_dev); + /* 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);
On Thursday 28 April 2016 22:37:19 Andrew Lunn wrote:
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
You are unfortunately reverting back to an older version of the patch which is harder to make compile on older kernels.
Kind regards, Sven
On Fri, Apr 29, 2016 at 07:52:42AM +0200, Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:19 Andrew Lunn wrote:
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
You are unfortunately reverting back to an older version of the patch which is harder to make compile on older kernels.
Hi Sven
Please point me at the version you would prefer.
Andrew
On Friday 29 April 2016 14:14:27 Andrew Lunn wrote:
On Fri, Apr 29, 2016 at 07:52:42AM +0200, Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:19 Andrew Lunn wrote:
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
You are unfortunately reverting back to an older version of the patch which is harder to make compile on older kernels.
Hi Sven
Please point me at the version you would prefer.
Partially this one: https://patchwork.open-mesh.org/patch/15921/
I know that your current submission doesn't contain the compat-patches part (which I find rather ugly) but this version has only a single function handling the batadv_getlink_net and thus could be easier to create some wild #defines working around the compat problem on older versions. But it will most likely end with a warning and being a big NOP on older kernels.
It is something like (untested):
/* WARNING dirty hack for batadv_getlink_net */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) #define get_link_net get_xstats_size || 1 || netdev->rtnl_link_ops->get_xstats_size #endif
It is the version of the "share your drugs" hack from earlier compat hacks.
Kind regards, Sven
On Friday 29 April 2016 14:59:21 Sven Eckelmann wrote:
On Friday 29 April 2016 14:14:27 Andrew Lunn wrote:
On Fri, Apr 29, 2016 at 07:52:42AM +0200, Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:19 Andrew Lunn wrote:
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
You are unfortunately reverting back to an older version of the patch which is harder to make compile on older kernels.
Hi Sven
Please point me at the version you would prefer.
Partially this one: https://patchwork.open-mesh.org/patch/15921/
I know that your current submission doesn't contain the compat-patches part (which I find rather ugly) but this version has only a single function handling the batadv_getlink_net and thus could be easier to create some wild #defines working around the compat problem on older versions. But it will most likely end with a warning and being a big NOP on older kernels.
It is something like (untested):
/* WARNING dirty hack for batadv_getlink_net */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) #define get_link_net get_xstats_size || 1 ||
netdev->rtnl_link_ops->get_xstats_size #endif
Attached is the patch version of the hack. It creates following warning:
/tmp/qemu-batman/batman-adv/net/batman-adv/hard-interface.c:103:9: warning: return makes pointer from integer without a cast [-Wint-conversion] return netdev->rtnl_link_ops->get_link_net(netdev); ^
If somebody else has a good/better idea then please post it.
Kind regards, Sven
On Thursday 28 April 2016 22:37:19 Andrew Lunn wrote:
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
net/batman-adv/hard-interface.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-)
You can find the missing includes in the attached patch
Kind regards, Sven
Debugfs is not netns aware. It thus has problems when the same interface name exists in multiple network name spaces.
Work around this by not creating entries for interfaces in name spaces other than the default name space. This means meshes in network namespaces cannot be managed via debugfs, but there will soon be a netlink interface which is netns aware.
Signed-off-by: Andrew Lunn andrew@lunn.ch --- net/batman-adv/debugfs.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 9529004..c6dd52a 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c @@ -78,7 +78,7 @@ static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log, debug_log->log_start = debug_log->log_end - batadv_log_buff_len; }
-__printf(2, 3) +_printf(2, 3) static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, const char *fmt, ...) { @@ -495,12 +495,16 @@ 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); struct batadv_debuginfo **bat_debug; struct dentry *file;
if (!batadv_debugfs) goto out;
+ if (net != &init_net) + return 0; + hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name, batadv_debugfs); if (!hard_iface->debug_dir) @@ -531,6 +535,11 @@ out: */ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface) { + struct net *net = dev_net(hard_iface->net_dev); + + if (net != &init_net) + return; + if (batadv_debugfs) { debugfs_remove_recursive(hard_iface->debug_dir); hard_iface->debug_dir = NULL; @@ -541,11 +550,15 @@ 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 *file;
if (!batadv_debugfs) goto out;
+ if (net != &init_net) + return 0; + bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs); if (!bat_priv->debug_dir) goto out; @@ -582,6 +595,10 @@ out: void batadv_debugfs_del_meshif(struct net_device *dev) { struct batadv_priv *bat_priv = netdev_priv(dev); + struct net *net = dev_net(dev); + + if (net != &init_net) + return;
batadv_debug_log_cleanup(bat_priv);
On Thursday 28 April 2016 22:37:20 Andrew Lunn wrote:
Debugfs is not netns aware. It thus has problems when the same interface name exists in multiple network name spaces.
Work around this by not creating entries for interfaces in name spaces other than the default name space. This means meshes in network namespaces cannot be managed via debugfs, but there will soon be a netlink interface which is netns aware.
Signed-off-by: Andrew Lunn andrew@lunn.ch
[...]
-__printf(2, 3) +_printf(2, 3) static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, const char *fmt, ...) {
I would really like to give this patch a Reviewed-by but this part seems to be an accident. It causes build errors:
$ make CONFIG_BATMAN_ADV_DEBUG=y KERNELPATH=/build_test/linux-build/linux-4.5 [...] CC [M] /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.o /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c:81:9: error: expected declaration specifiers or ‘...’ before numeric constant _printf(2, 3) ^ /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c:81:12: error: expected declaration specifiers or ‘...’ before numeric constant _printf(2, 3) ^ /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c: In function ‘batadv_debug_log’: /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c:114:2: error: implicit declaration of function ‘batadv_fdebug_log’ [-Werror=implicit-function-declaration] batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s", ^ /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c: At top level: /tmp/qemu-batman/batman-adv/net/batman-adv/debugfs.c:68:13: warning: ‘batadv_emit_log_char’ defined but not used [-Wunused-function] static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log, ^
Kind regards, Sven
On Fri, Apr 29, 2016 at 08:07:18PM +0200, Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:20 Andrew Lunn wrote:
Debugfs is not netns aware. It thus has problems when the same interface name exists in multiple network name spaces.
Work around this by not creating entries for interfaces in name spaces other than the default name space. This means meshes in network namespaces cannot be managed via debugfs, but there will soon be a netlink interface which is netns aware.
Signed-off-by: Andrew Lunn andrew@lunn.ch
[...]
-__printf(2, 3) +_printf(2, 3) static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, const char *fmt, ...) {
I would really like to give this patch a Reviewed-by but this part seems to be an accident.
Agreed. This should not be changed.
Andrew
On Thursday 28 April 2016 22:37:20 Andrew Lunn wrote:
Debugfs is not netns aware. It thus has problems when the same interface name exists in multiple network name spaces.
Work around this by not creating entries for interfaces in name spaces other than the default name space. This means meshes in network namespaces cannot be managed via debugfs, but there will soon be a netlink interface which is netns aware.
Signed-off-by: Andrew Lunn andrew@lunn.ch
net/batman-adv/debugfs.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
You can find the missing includes in the attached patch
Kind regards, Sven
From: Matthias Schiffer mschiffer@universe-factory.net
debugfs is currently severely broken virtually everywhere in the kernel where files are dynamically added and removed (see http://lkml.iu.edu/hypermail/linux/kernel/1506.1/02196.html for some details). In addition to that, debugfs is not namespace-aware.
Also, the debugfs interface will try to fix the whole list of originators/ TT entries into a single buffer. The situation has improved in recent kernels,as the seq_file infrastructure will fall back to vmalloc now when kmalloc fails. Still, converting all information to text and potentially retrying multiple times until the buffer is big enough is very inefficient.
This commit adds generic infrastructur for the netlink interface to batman-adv and implements the following command:
* BATADV_CMD_GET_ROUTING_ALGOS: will return the list of supported routing algorithms * BATADV_CMD_GET_MESH_INFO: will return basic information about a batman-adv softif (name, index and MAC address for both the softif and the primary hardif; routing algorithm; batman-adv version) * BATADV_CMD_GET_HARDIFS: will return the list of hardifs (including index, name and MAC address) of all hardifs for a given softif
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net --- Makefile | 1 + include/uapi/linux/batman_adv.h | 49 ++++++++ net/batman-adv/Makefile | 1 + net/batman-adv/main.c | 48 ++++++++ net/batman-adv/main.h | 1 + net/batman-adv/netlink.c | 251 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/netlink.h | 36 ++++++ 7 files changed, 387 insertions(+) create mode 100644 include/uapi/linux/batman_adv.h create mode 100644 net/batman-adv/netlink.c create mode 100644 net/batman-adv/netlink.h
diff --git a/Makefile b/Makefile index 5d2c058..f17bde5 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,7 @@ REVISION= $(shell if [ -d "$(PWD)/.git" ]; then \ fi) export NOSTDINC_FLAGS := \ -I$(PWD)/compat-include/ \ + -I$(PWD)/include/ \ -include $(PWD)/compat.h \ $(CFLAGS)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h new file mode 100644 index 0000000..b9b7dfd --- /dev/null +++ b/include/uapi/linux/batman_adv.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * 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/. + */ + +#ifndef _UAPI_LINUX_BATMAN_ADV_H_ +#define _UAPI_LINUX_BATMAN_ADV_H_ + +#define BATADV_NL_NAME "batadv" + +enum { + BATADV_ATTR_UNSPEC, + BATADV_ATTR_VERSION, + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_MESH_IFNAME, + BATADV_ATTR_MESH_ADDRESS, + BATADV_ATTR_HARD_IFINDEX, + BATADV_ATTR_HARD_IFNAME, + BATADV_ATTR_HARD_ADDRESS, + BATADV_ATTR_ACTIVE, + __BATADV_ATTR_MAX, +}; + +#define BATADV_ATTR_MAX (__BATADV_ATTR_MAX - 1) + +enum { + BATADV_CMD_UNSPEC, + BATADV_CMD_GET_ROUTING_ALGOS, + BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_GET_HARDIFS, + __BATADV_CMD_MAX, +}; + +#define BATADV_CMD_MAX (__BATADV_CMD_MAX - 1) + +#endif /* _UAPI_LINUX_BATMAN_ADV_H_ */ diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index 797cf2f..4e5adba 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -33,6 +33,7 @@ batman-adv-y += hash.o batman-adv-y += icmp_socket.o batman-adv-y += main.o batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o +batman-adv-y += netlink.o batman-adv-$(CONFIG_BATMAN_ADV_NC) += network-coding.o batman-adv-y += originator.o batman-adv-y += routing.o diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 5f2974b..05fc597 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -47,6 +47,7 @@ #include <linux/workqueue.h> #include <net/dsfield.h> #include <net/rtnetlink.h> +#include <uapi/linux/batman_adv.h>
#include "bat_algo.h" #include "bridge_loop_avoidance.h" @@ -57,6 +58,7 @@ #include "hard-interface.h" #include "icmp_socket.h" #include "multicast.h" +#include "netlink.h" #include "network-coding.h" #include "originator.h" #include "packet.h" @@ -101,6 +103,7 @@ static int __init batadv_init(void)
register_netdevice_notifier(&batadv_hard_if_notifier); rtnl_link_register(&batadv_link_ops); + batadv_netlink_register();
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION); @@ -111,6 +114,7 @@ static int __init batadv_init(void) static void __exit batadv_exit(void) { batadv_debugfs_destroy(); + batadv_netlink_unregister(); rtnl_link_unregister(&batadv_link_ops); unregister_netdevice_notifier(&batadv_hard_if_notifier); batadv_hardif_remove_interfaces(); @@ -610,6 +614,50 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset) return 0; }
+static int batadv_algo_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_algo_ops *bat_algo_ops) +{ + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_ROUTING_ALGOS); + if (!hdr) + return -EMSGSIZE; + + if (nla_put_string(msg, BATADV_ATTR_ALGO_NAME, bat_algo_ops->name)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + int portid = NETLINK_CB(cb->skb).portid; + struct batadv_algo_ops *bat_algo_ops; + int skip = cb->args[0]; + int i = 0; + + hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) { + if (i++ < skip) + continue; + + if (batadv_algo_dump_entry(msg, portid, cb->nlh->nlmsg_seq, + bat_algo_ops)) { + i--; + break; + } + } + + cb->args[0] = i; + + return msg->len; +} + /** * batadv_skb_crc32 - calculate CRC32 of the whole packet and skip bytes in * the header diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 7692526..eddbb59 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -221,6 +221,7 @@ void batadv_recv_handler_unregister(u8 packet_type); int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); +int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb); __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr);
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c new file mode 100644 index 0000000..6682f78 --- /dev/null +++ b/net/batman-adv/netlink.c @@ -0,0 +1,251 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * 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/. + */ + +#include "main.h" +#include "netlink.h" + +#include <linux/netdevice.h> +#include <net/sock.h> +#include <uapi/linux/batman_adv.h> + +#include "hard-interface.h" +#include "originator.h" +#include "soft-interface.h" +#include "translation-table.h" + +struct genl_family batadv_netlink_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = BATADV_NL_NAME, + .version = 1, + .maxattr = BATADV_ATTR_MAX, +}; + +static int +batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) +{ + int ret = -ENOBUFS; + struct batadv_priv *bat_priv = netdev_priv(soft_iface); + struct batadv_hard_iface *primary_if = NULL; + struct net_device *hard_iface; + + if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || + nla_put_string(msg, BATADV_ATTR_ALGO_NAME, + bat_priv->bat_algo_ops->name) || + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) || + nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) || + nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN, + soft_iface->dev_addr)) + goto out; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) { + hard_iface = primary_if->net_dev; + + if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + hard_iface->ifindex) || + nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, + hard_iface->name) || + nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, + hard_iface->dev_addr)) + goto out; + } + + ret = 0; + + out: + if (primary_if) + batadv_hardif_put(primary_if); + + return ret; +} + +static int +batadv_netlink_get_mesh_info(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = genl_info_net(info); + int ret; + struct sk_buff *msg = NULL; + void *msg_head; + int ifindex; + struct net_device *soft_iface; + + if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq, + &batadv_netlink_family, 0, + BATADV_CMD_GET_MESH_INFO); + if (!msg_head) { + ret = -ENOBUFS; + goto out; + } + + ret = batadv_netlink_mesh_info_put(msg, soft_iface); + + out: + if (soft_iface) + dev_put(soft_iface); + + if (ret) { + if (msg) + nlmsg_free(msg); + return ret; + } + + genlmsg_end(msg, msg_head); + return genlmsg_reply(msg, info); +} + +static int +batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_hard_iface *hard_iface) +{ + struct net_device *net_dev = hard_iface->net_dev; + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_HARDIFS); + if (!hdr) + return -EMSGSIZE; + + if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + net_dev->ifindex) || + nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, + net_dev->name) || + nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, + net_dev->dev_addr)) + goto nla_put_failure; + + if (hard_iface->if_status == BATADV_IF_ACTIVE) { + if (nla_put_flag(msg, BATADV_ATTR_ACTIVE)) + goto nla_put_failure; + } + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface; + struct batadv_hard_iface *hard_iface; + int ifindex; + int portid = NETLINK_CB(cb->skb).portid; + int seq = cb->nlh->nlmsg_seq; + int skip = cb->args[0]; + int i = 0; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface) + return -ENODEV; + + if (!batadv_softif_is_valid(soft_iface)) { + dev_put(soft_iface); + return -ENODEV; + } + + rcu_read_lock(); + + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->soft_iface != soft_iface) + continue; + + if (i++ < skip) + continue; + + if (batadv_netlink_dump_hardif_entry(msg, portid, seq, + hard_iface)) { + i--; + break; + } + } + + rcu_read_unlock(); + + dev_put(soft_iface); + + cb->args[0] = i; + + return msg->len; +} + +static struct nla_policy batadv_netlink_policy[BATADV_ATTR_MAX + 1] = { + [BATADV_ATTR_MESH_IFINDEX] = { .type = NLA_U32 }, +}; + +static struct genl_ops batadv_netlink_ops[] = { + { + .cmd = BATADV_CMD_GET_ROUTING_ALGOS, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_algo_dump, + }, + { + .cmd = BATADV_CMD_GET_MESH_INFO, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .doit = batadv_netlink_get_mesh_info, + }, + { + .cmd = BATADV_CMD_GET_HARDIFS, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_netlink_dump_hardifs, + }, +}; + +void __init batadv_netlink_register(void) +{ + int ret; + + ret = genl_register_family_with_ops(&batadv_netlink_family, + batadv_netlink_ops); + if (ret) + pr_warn("unable to register netlink family"); +} + +void batadv_netlink_unregister(void) +{ + genl_unregister_family(&batadv_netlink_family); +} diff --git a/net/batman-adv/netlink.h b/net/batman-adv/netlink.h new file mode 100644 index 0000000..31022d4 --- /dev/null +++ b/net/batman-adv/netlink.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2016 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + * + * 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/. + */ + +#ifndef _NET_BATMAN_ADV_NETLINK_H_ +#define _NET_BATMAN_ADV_NETLINK_H_ + +#include <net/genetlink.h> + +void batadv_netlink_register(void); +void batadv_netlink_unregister(void); + +static inline int +batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) +{ + struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype); + + return attr ? nla_get_u32(attr) : 0; +} + +extern struct genl_family batadv_netlink_family; + +#endif /* _NET_BATMAN_ADV_NETLINK_H_ */
On Thursday 28 April 2016 22:37:21 Andrew Lunn wrote: [...] | 1 +
include/uapi/linux/batman_adv.h | 49 ++++++++
Just as reminder for the person submitting to the kernel:
Please add the file entry to the MAINTAINERS file.
Kind regards, Sven`
On Thursday 28 April 2016 22:37:21 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
debugfs is currently severely broken virtually everywhere in the kernel where files are dynamically added and removed (see http://lkml.iu.edu/hypermail/linux/kernel/1506.1/02196.html for some details). In addition to that, debugfs is not namespace-aware.
Also, the debugfs interface will try to fix the whole list of originators/ TT entries into a single buffer. The situation has improved in recent kernels,as the seq_file infrastructure will fall back to vmalloc now when kmalloc fails. Still, converting all information to text and potentially retrying multiple times until the buffer is big enough is very inefficient.
This commit adds generic infrastructur for the netlink interface to batman-adv and implements the following command:
- BATADV_CMD_GET_ROUTING_ALGOS: will return the list of supported routing algorithms
- BATADV_CMD_GET_MESH_INFO: will return basic information about a batman-adv softif (name, index and MAC address for both the softif and the primary hardif; routing algorithm; batman-adv version)
- BATADV_CMD_GET_HARDIFS: will return the list of hardifs (including index, name and MAC address) of all hardifs for a given softif
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
Makefile | 1 + include/uapi/linux/batman_adv.h | 49 ++++++++ net/batman-adv/Makefile | 1 + net/batman-adv/main.c | 48 ++++++++ net/batman-adv/main.h | 1 + net/batman-adv/netlink.c | 251 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/netlink.h | 36 ++++++ 7 files changed, 387 insertions(+) create mode 100644 include/uapi/linux/batman_adv.h create mode 100644 net/batman-adv/netlink.c create mode 100644 net/batman-adv/netlink.h
You can find the missing includes in the attached patch
Kind regards, Sven
On Thursday 28 April 2016 22:37:21 Andrew Lunn wrote: [....]
+int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb) +{
- int portid = NETLINK_CB(cb->skb).portid;
This doesn't build on older kernels because the name of this field was changed. Attached is a patch which should work(tm).
This was already discussed here: https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2016-April/014880.html
But there is now still the problem that info->snd_portid was previously called info->snd_pid. Also the genl_register_family_with_ops compat has to be added.
Kind regards, Sven
On Friday 29 April 2016 21:55:32 Sven Eckelmann wrote: [...]
But there is now still the problem that info->snd_portid was previously called info->snd_pid. Also the genl_register_family_with_ops compat has to be added.
I don't have a better idea for the snd_portid right now than the attached patch.
The seems to be already solved by backports.git but I will not try to understand their hacks tonight.
https://git.kernel.org/cgit/linux/kernel/git/backports/backports.git/tree/ba...
Kind regards, Sven
On Friday 29 April 2016 21:55:32 Sven Eckelmann wrote: [...]
But there is now still the problem that info->snd_portid was previously called info->snd_pid. Also the genl_register_family_with_ops compat has to be added.
And here is also the one for genl_register_family_with_ops.
Kind regards, Sven
From: Matthias Schiffer mschiffer@universe-factory.net
This adds the commands BATADV_CMD_GET_TRANSTABLE_LOCAL and BATADV_CMD_GET_TRANSTABLE_GLOBAL, which correspond to the transtable_local and transtable_global debugfs files.
The batadv_tt_client_flags enum is moved to the UAPI to expose it as part of the netlink API.
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net --- include/uapi/linux/batman_adv.h | 47 ++++++ net/batman-adv/netlink.c | 12 ++ net/batman-adv/packet.h | 36 ----- net/batman-adv/translation-table.c | 305 +++++++++++++++++++++++++++++++++++++ net/batman-adv/translation-table.h | 2 + 5 files changed, 366 insertions(+), 36 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index b9b7dfd..25dee3c 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -20,6 +20,42 @@
#define BATADV_NL_NAME "batadv"
+/** + * enum batadv_tt_client_flags - TT client specific flags + * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table + * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new + * update telling its new real location has not been received/sent yet + * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface. + * This information is used by the "AP Isolation" feature + * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This + * information is used by the Extended Isolation feature + * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table + * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has + * not been announced yet + * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept + * in the table for one more originator interval for consistency purposes + * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of + * the network but no nnode has already announced it + * + * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. + * Bits from 8 to 15 are called _local flags_ because they are used for local + * computations only. + * + * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with + * the other nodes in the network. To achieve this goal these flags are included + * in the TT CRC computation. + */ +enum batadv_tt_client_flags { + BATADV_TT_CLIENT_DEL = (1 << 0), + BATADV_TT_CLIENT_ROAM = (1 << 1), + BATADV_TT_CLIENT_WIFI = (1 << 4), + BATADV_TT_CLIENT_ISOLA = (1 << 5), + BATADV_TT_CLIENT_NOPURGE = (1 << 8), + BATADV_TT_CLIENT_NEW = (1 << 9), + BATADV_TT_CLIENT_PENDING = (1 << 10), + BATADV_TT_CLIENT_TEMP = (1 << 11), +}; + enum { BATADV_ATTR_UNSPEC, BATADV_ATTR_VERSION, @@ -31,6 +67,15 @@ enum { BATADV_ATTR_HARD_IFNAME, BATADV_ATTR_HARD_ADDRESS, BATADV_ATTR_ACTIVE, + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_TT_ADDRESS, + BATADV_ATTR_TT_TTVN, + BATADV_ATTR_TT_LAST_TTVN, + BATADV_ATTR_TT_CRC32, + BATADV_ATTR_TT_VID, + BATADV_ATTR_TT_FLAGS, + BATADV_ATTR_FLAG_BEST, + BATADV_ATTR_LAST_SEEN_MSECS, __BATADV_ATTR_MAX, };
@@ -41,6 +86,8 @@ enum { BATADV_CMD_GET_ROUTING_ALGOS, BATADV_CMD_GET_MESH_INFO, BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_TRANSTABLE_LOCAL, + BATADV_CMD_GET_TRANSTABLE_GLOBAL, __BATADV_CMD_MAX, };
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 6682f78..50047d4 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -233,6 +233,18 @@ static struct genl_ops batadv_netlink_ops[] = { .policy = batadv_netlink_policy, .dumpit = batadv_netlink_dump_hardifs, }, + { + .cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_tt_local_dump, + }, + { + .cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_tt_global_dump, + }, };
void __init batadv_netlink_register(void) diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 372128d..b45460d 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -126,42 +126,6 @@ enum batadv_tt_data_flags { };
/** - * enum batadv_tt_client_flags - TT client specific flags - * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table - * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new - * update telling its new real location has not been received/sent yet - * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface. - * This information is used by the "AP Isolation" feature - * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This - * information is used by the Extended Isolation feature - * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table - * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has - * not been announced yet - * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept - * in the table for one more originator interval for consistency purposes - * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of - * the network but no nnode has already announced it - * - * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. - * Bits from 8 to 15 are called _local flags_ because they are used for local - * computations only. - * - * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with - * the other nodes in the network. To achieve this goal these flags are included - * in the TT CRC computation. - */ -enum batadv_tt_client_flags { - BATADV_TT_CLIENT_DEL = BIT(0), - BATADV_TT_CLIENT_ROAM = BIT(1), - BATADV_TT_CLIENT_WIFI = BIT(4), - BATADV_TT_CLIENT_ISOLA = BIT(5), - BATADV_TT_CLIENT_NOPURGE = BIT(8), - BATADV_TT_CLIENT_NEW = BIT(9), - BATADV_TT_CLIENT_PENDING = BIT(10), - BATADV_TT_CLIENT_TEMP = BIT(11), -}; - -/** * enum batadv_vlan_flags - flags for the four MSB of any vlan ID field * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not */ diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index feaf492..cd3e4f2 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -43,11 +43,15 @@ #include <linux/stddef.h> #include <linux/string.h> #include <linux/workqueue.h> +#include <net/net_namespace.h> +#include <net/sock.h> +#include <uapi/linux/batman_adv.h>
#include "bridge_loop_avoidance.h" #include "hard-interface.h" #include "hash.h" #include "multicast.h" +#include "netlink.h" #include "originator.h" #include "packet.h" #include "soft-interface.h" @@ -1056,6 +1060,138 @@ out: return 0; }
+static int +batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_tt_common_entry *common) +{ + void *hdr; + struct batadv_softif_vlan *vlan; + struct batadv_tt_local_entry *local; + unsigned int last_seen_msecs; + u32 crc; + + local = container_of(common, struct batadv_tt_local_entry, common); + last_seen_msecs = jiffies_to_msecs(jiffies - local->last_seen); + + vlan = batadv_softif_vlan_get(bat_priv, common->vid); + if (!vlan) + return 0; + + crc = vlan->tt.crc; + + batadv_softif_vlan_put(vlan); + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_TRANSTABLE_LOCAL); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || + nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) || + nla_put_u16(msg, BATADV_ATTR_TT_VID, + BATADV_PRINT_VID(common->vid)) || + nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags)) + goto nla_put_failure; + + if (!(common->flags & BATADV_TT_CLIENT_NOPURGE)) { + if (nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, + last_seen_msecs)) + goto nla_put_failure; + } + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct hlist_head *head, int *idx_s) +{ + struct batadv_tt_common_entry *common; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(common, head, hash_entry) { + if (idx++ < *idx_s) + continue; + + if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv, + common)) { + rcu_read_unlock(); + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + rcu_read_unlock(); + + *idx_s = 0; + return 0; +} + +int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface = NULL; + struct batadv_priv *bat_priv; + struct batadv_hard_iface *primary_if = NULL; + struct batadv_hashtable *hash; + struct hlist_head *head; + int ret; + int ifindex; + int bucket = cb->args[0]; + int idx = cb->args[1]; + int portid = NETLINK_CB(cb->skb).portid; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + hash = bat_priv->tt.local_hash; + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq, + bat_priv, head, &idx)) + break; + + bucket++; + } + + ret = msg->len; + + out: + if (primary_if) + batadv_hardif_put(primary_if); + if (soft_iface) + dev_put(soft_iface); + + cb->args[0] = bucket; + cb->args[1] = idx; + + return ret; +} + static void batadv_tt_local_set_pending(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, @@ -1702,6 +1838,175 @@ out: return 0; }
+static int +batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_tt_common_entry *common, + struct batadv_tt_orig_list_entry *orig, + bool best) +{ + void *hdr; + struct batadv_orig_node_vlan *vlan; + u8 last_ttvn; + u32 crc; + + vlan = batadv_orig_node_vlan_get(orig->orig_node, + common->vid); + if (!vlan) + return 0; + + crc = vlan->tt.crc; + + batadv_orig_node_vlan_put(vlan); + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_TRANSTABLE_GLOBAL); + if (!hdr) + return -ENOBUFS; + + last_ttvn = atomic_read(&orig->orig_node->last_ttvn); + + if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || + nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, + orig->orig_node->orig) || + nla_put_u8(msg, BATADV_ATTR_TT_TTVN, orig->ttvn) || + nla_put_u8(msg, BATADV_ATTR_TT_LAST_TTVN, last_ttvn) || + nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) || + nla_put_u16(msg, BATADV_ATTR_TT_VID, + BATADV_PRINT_VID(common->vid)) || + nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags)) + goto nla_put_failure; + + if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_tt_global_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_tt_common_entry *common, int *sub_s) +{ + struct batadv_tt_orig_list_entry *orig_entry, *best_entry; + struct batadv_tt_global_entry *global; + struct hlist_head *head; + int sub = 0; + bool best; + + global = container_of(common, struct batadv_tt_global_entry, common); + best_entry = batadv_transtable_best_orig(bat_priv, global); + head = &global->orig_list; + + hlist_for_each_entry_rcu(orig_entry, head, list) { + if (sub++ < *sub_s) + continue; + + best = (orig_entry == best_entry); + + if (batadv_tt_global_dump_subentry(msg, portid, seq, common, + orig_entry, best)) { + *sub_s = sub - 1; + return -EMSGSIZE; + } + } + + *sub_s = 0; + return 0; +} + +static int +batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct hlist_head *head, int *idx_s, int *sub) +{ + struct batadv_tt_common_entry *common; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(common, head, hash_entry) { + if (idx++ < *idx_s) + continue; + + if (batadv_tt_global_dump_entry(msg, portid, seq, bat_priv, + common, sub)) { + rcu_read_unlock(); + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + rcu_read_unlock(); + + *idx_s = 0; + *sub = 0; + return 0; +} + +int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface = NULL; + struct batadv_priv *bat_priv; + struct batadv_hard_iface *primary_if = NULL; + struct batadv_hashtable *hash; + struct hlist_head *head; + int ret; + int ifindex; + int bucket = cb->args[0]; + int idx = cb->args[1]; + int sub = cb->args[2]; + int portid = NETLINK_CB(cb->skb).portid; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + hash = bat_priv->tt.global_hash; + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_tt_global_dump_bucket(msg, portid, + cb->nlh->nlmsg_seq, bat_priv, + head, &idx, &sub)) + break; + + bucket++; + } + + ret = msg->len; + + out: + if (primary_if) + batadv_hardif_put(primary_if); + if (soft_iface) + dev_put(soft_iface); + + cb->args[0] = bucket; + cb->args[1] = idx; + cb->args[2] = sub; + + return ret; +} + /** * _batadv_tt_global_del_orig_entry - remove and free an orig_entry * @tt_global_entry: the global entry to remove the orig_entry from diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 7c7e2c0..6d8b5b2 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -33,6 +33,8 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const char *message, bool roaming); int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); +int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb); +int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb); void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, s32 match_vid, const char *message);
On Thursday 28 April 2016 22:37:22 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
This adds the commands BATADV_CMD_GET_TRANSTABLE_LOCAL and BATADV_CMD_GET_TRANSTABLE_GLOBAL, which correspond to the transtable_local and transtable_global debugfs files.
The batadv_tt_client_flags enum is moved to the UAPI to expose it as part of the netlink API.
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
include/uapi/linux/batman_adv.h | 47 ++++++ net/batman-adv/netlink.c | 12 ++ net/batman-adv/packet.h | 36 ----- net/batman-adv/translation-table.c | 305 +++++++++++++++++++++++++++++++++++++ net/batman-adv/translation-table.h | 2 + 5 files changed, 366 insertions(+), 36 deletions(-)
You can find the missing includes in the attached patch
Kind regards, Sven
From: Matthias Schiffer mschiffer@universe-factory.net
Add BATADV_CMD_GET_ORIGINATORS and BATADV_CMD_GET_NEIGHBORS commands, using handlers bat_orig_dump and bat_neigh_dump in batadv_algo_ops. Will always return -EOPNOTSUPP for now, as no implementations exist yet.
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net --- include/uapi/linux/batman_adv.h | 2 + net/batman-adv/netlink.c | 13 ++++ net/batman-adv/originator.c | 142 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/originator.h | 2 + net/batman-adv/types.h | 7 ++ 5 files changed, 166 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 25dee3c..35d8e8c 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -88,6 +88,8 @@ enum { BATADV_CMD_GET_HARDIFS, BATADV_CMD_GET_TRANSTABLE_LOCAL, BATADV_CMD_GET_TRANSTABLE_GLOBAL, + BATADV_CMD_GET_ORIGINATORS, + BATADV_CMD_GET_NEIGHBORS, __BATADV_CMD_MAX, };
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 50047d4..3b40eb5 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -212,6 +212,7 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
static struct nla_policy batadv_netlink_policy[BATADV_ATTR_MAX + 1] = { [BATADV_ATTR_MESH_IFINDEX] = { .type = NLA_U32 }, + [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 }, };
static struct genl_ops batadv_netlink_ops[] = { @@ -245,6 +246,18 @@ static struct genl_ops batadv_netlink_ops[] = { .policy = batadv_netlink_policy, .dumpit = batadv_tt_global_dump, }, + { + .cmd = BATADV_CMD_GET_ORIGINATORS, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_orig_dump, + }, + { + .cmd = BATADV_CMD_GET_NEIGHBORS, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_hardif_neigh_dump, + }, };
void __init batadv_netlink_register(void) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1ff4ee4..3e053e1 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -33,6 +33,8 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> +#include <net/sock.h> +#include <uapi/linux/batman_adv.h>
#include "distributed-arp-table.h" #include "fragmentation.h" @@ -40,8 +42,10 @@ #include "hard-interface.h" #include "hash.h" #include "multicast.h" +#include "netlink.h" #include "network-coding.h" #include "routing.h" +#include "soft-interface.h" #include "translation-table.h"
/* hash class keys */ @@ -698,6 +702,75 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset) return 0; }
+int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface = NULL; + struct net_device *hard_iface = NULL; + struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT; + struct batadv_priv *bat_priv; + struct batadv_hard_iface *primary_if = NULL; + int ret; + int ifindex, hard_ifindex; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + hard_ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_HARD_IFINDEX); + if (hard_ifindex) { + hard_iface = dev_get_by_index(net, hard_ifindex); + if (hard_iface) + hardif = batadv_hardif_get_by_netdev(hard_iface); + + if (!hardif) { + ret = -ENODEV; + goto out; + } + + if (hardif->soft_iface != soft_iface) { + ret = -ENOENT; + goto out; + } + } + + if (!bat_priv->bat_algo_ops->bat_neigh_dump) { + ret = -EOPNOTSUPP; + goto out; + } + + bat_priv->bat_algo_ops->bat_neigh_dump(msg, cb, bat_priv, hardif); + + ret = msg->len; + + out: + if (hardif) + batadv_hardif_put(hardif); + if (hard_iface) + dev_put(hard_iface); + if (primary_if) + batadv_hardif_put(primary_if); + if (soft_iface) + dev_put(soft_iface); + + return ret; +} + /** * batadv_orig_ifinfo_release - release orig_ifinfo from lists and queue for * free after rcu grace period @@ -1294,6 +1367,75 @@ out: return 0; }
+int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface = NULL; + struct net_device *hard_iface = NULL; + struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT; + struct batadv_priv *bat_priv; + struct batadv_hard_iface *primary_if = NULL; + int ret; + int ifindex, hard_ifindex; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + hard_ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_HARD_IFINDEX); + if (hard_ifindex) { + hard_iface = dev_get_by_index(net, hard_ifindex); + if (hard_iface) + hardif = batadv_hardif_get_by_netdev(hard_iface); + + if (!hardif) { + ret = -ENODEV; + goto out; + } + + if (hardif->soft_iface != soft_iface) { + ret = -ENOENT; + goto out; + } + } + + if (!bat_priv->bat_algo_ops->bat_orig_dump) { + ret = -EOPNOTSUPP; + goto out; + } + + bat_priv->bat_algo_ops->bat_orig_dump(msg, cb, bat_priv, hardif); + + ret = msg->len; + + out: + if (hardif) + batadv_hardif_put(hardif); + if (hard_iface) + dev_put(hard_iface); + if (primary_if) + batadv_hardif_put(primary_if); + if (soft_iface) + dev_put(soft_iface); + + return ret; +} + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num) { diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 64a8951..a8eb520 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -61,6 +61,7 @@ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo);
+int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset);
struct batadv_orig_ifinfo * @@ -72,6 +73,7 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); +int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 6a577f4..cbe98a8 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -28,6 +28,7 @@ #include <linux/if_ether.h> #include <linux/kref.h> #include <linux/netdevice.h> +#include <linux/netlink.h> #include <linux/sched.h> /* for linux/wait.h */ #include <linux/spinlock.h> #include <linux/types.h> @@ -1311,9 +1312,15 @@ struct batadv_algo_ops { struct batadv_hard_iface *if_outgoing2); void (*bat_neigh_print)(struct batadv_priv *priv, struct seq_file *seq); void (*bat_neigh_free)(struct batadv_neigh_node *neigh); + void (*bat_neigh_dump)(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *priv, + struct batadv_hard_iface *hard_iface); /* orig_node handling API */ void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq, struct batadv_hard_iface *hard_iface); + void (*bat_orig_dump)(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *priv, + struct batadv_hard_iface *hard_iface); void (*bat_orig_free)(struct batadv_orig_node *orig_node); int (*bat_orig_add_if)(struct batadv_orig_node *orig_node, int max_if_num);
On Thursday 28 April 2016 22:37:23 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
Add BATADV_CMD_GET_ORIGINATORS and BATADV_CMD_GET_NEIGHBORS commands, using handlers bat_orig_dump and bat_neigh_dump in batadv_algo_ops. Will always return -EOPNOTSUPP for now, as no implementations exist yet.
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
include/uapi/linux/batman_adv.h | 2 + net/batman-adv/netlink.c | 13 ++++ net/batman-adv/originator.c | 142 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/originator.h | 2 + net/batman-adv/types.h | 7 ++ 5 files changed, 166 insertions(+)
You can find the missing includes in the attached patch
Kind regards, Sven
On Thursday 28 April 2016 22:37:23 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
Add BATADV_CMD_GET_ORIGINATORS and BATADV_CMD_GET_NEIGHBORS commands, using handlers bat_orig_dump and bat_neigh_dump in batadv_algo_ops. Will always return -EOPNOTSUPP for now, as no implementations exist yet.
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
[...]
@@ -1311,9 +1312,15 @@ struct batadv_algo_ops { struct batadv_hard_iface *if_outgoing2); void (*bat_neigh_print)(struct batadv_priv *priv, struct seq_file *seq); void (*bat_neigh_free)(struct batadv_neigh_node *neigh);
- void (*bat_neigh_dump)(struct sk_buff *msg, struct netlink_callback *cb,
struct batadv_priv *priv,
/* orig_node handling API */ void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq, struct batadv_hard_iface *hard_iface);struct batadv_hard_iface *hard_iface);
- void (*bat_orig_dump)(struct sk_buff *msg, struct netlink_callback *cb,
struct batadv_priv *priv,
void (*bat_orig_free)(struct batadv_orig_node *orig_node); int (*bat_orig_add_if)(struct batadv_orig_node *orig_node, int max_if_num);struct batadv_hard_iface *hard_iface);
Kernel-doc is missing for these two new entries.
Kind regards, Sven
From: Matthias Schiffer mschiffer@universe-factory.net
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net --- include/uapi/linux/batman_adv.h | 2 + net/batman-adv/bat_iv_ogm.c | 268 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 35d8e8c..baf4ac8 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -76,6 +76,8 @@ enum { BATADV_ATTR_TT_FLAGS, BATADV_ATTR_FLAG_BEST, BATADV_ATTR_LAST_SEEN_MSECS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, __BATADV_ATTR_MAX, };
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index ce2f203..e70560e 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -47,10 +47,12 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/workqueue.h> +#include <uapi/linux/batman_adv.h>
#include "bitarray.h" #include "hard-interface.h" #include "hash.h" +#include "netlink.h" #include "network-coding.h" #include "originator.h" #include "packet.h" @@ -1918,6 +1920,171 @@ next: seq_puts(seq, "No batman nodes in range ...\n"); }
+static bool +batadv_iv_ogm_neigh_get_tq_avg(struct batadv_neigh_node *neigh_node, + struct batadv_hard_iface *if_outgoing, + u8 *tq_avg) +{ + struct batadv_neigh_ifinfo *n_ifinfo; + + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); + if (!n_ifinfo) + return false; + + *tq_avg = n_ifinfo->bat_iv.tq_avg; + batadv_neigh_ifinfo_put(n_ifinfo); + + return true; +} + +static int +batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct batadv_orig_node *orig_node, + struct batadv_neigh_node *neigh_node, + bool best) +{ + void *hdr; + u8 tq_avg; + unsigned int last_seen_msecs; + + last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen); + + if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node, if_outgoing, &tq_avg)) + return 0; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_ORIGINATORS); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) || + nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, + neigh_node->addr) || + nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + neigh_node->if_incoming->net_dev->ifindex) || + nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) || + nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, + last_seen_msecs)) + goto nla_put_failure; + + if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_iv_ogm_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct batadv_orig_node *orig_node, int *sub_s) +{ + struct batadv_neigh_node *neigh_node_best; + struct batadv_neigh_node *neigh_node; + int sub = 0; + bool best; + u8 tq_avg_best; + + neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing); + if (!neigh_node_best) + goto out; + + if (!batadv_iv_ogm_neigh_get_tq_avg(neigh_node_best, if_outgoing, + &tq_avg_best)) + goto out; + + if (tq_avg_best == 0) + goto out; + + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { + if (sub++ < *sub_s) + continue; + + best = (neigh_node == neigh_node_best); + + if (batadv_iv_ogm_orig_dump_subentry(msg, portid, seq, bat_priv, + if_outgoing, orig_node, + neigh_node, best)) { + batadv_neigh_node_put(neigh_node_best); + + *sub_s = sub - 1; + return -EMSGSIZE; + } + } + + out: + if (neigh_node_best) + batadv_neigh_node_put(neigh_node_best); + + *sub_s = 0; + return 0; +} + +static int +batadv_iv_ogm_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct hlist_head *head, int *idx_s, int *sub) +{ + struct batadv_orig_node *orig_node; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, head, hash_entry) { + if (idx++ < *idx_s) + continue; + + if (batadv_iv_ogm_orig_dump_entry(msg, portid, seq, bat_priv, + if_outgoing, orig_node, + sub)) { + rcu_read_unlock(); + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + rcu_read_unlock(); + + *idx_s = 0; + *sub = 0; + return 0; +} + +static void +batadv_iv_ogm_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_hashtable *hash = bat_priv->orig_hash; + struct hlist_head *head; + int bucket = cb->args[0]; + int idx = cb->args[1]; + int sub = cb->args[2]; + int portid = NETLINK_CB(cb->skb).portid; + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_iv_ogm_orig_dump_bucket(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, if_outgoing, head, + &idx, &sub)) + break; + + bucket++; + } + + cb->args[0] = bucket; + cb->args[1] = idx; + cb->args[2] = sub; +} + /** * batadv_iv_hardif_neigh_print - print a single hop neighbour node * @seq: neighbour table seq_file struct @@ -1969,6 +2136,105 @@ static void batadv_iv_neigh_print(struct batadv_priv *bat_priv, seq_puts(seq, "No batman nodes in range ...\n"); }
+static int +batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_hardif_neigh_node *hardif_neigh) +{ + void *hdr; + unsigned int last_seen_msecs; + + last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_NEIGHBORS); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, + hardif_neigh->addr) || + nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + hardif_neigh->if_incoming->net_dev->ifindex) || + nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, + last_seen_msecs)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_iv_ogm_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface, + int *idx_s) +{ + struct batadv_hardif_neigh_node *hardif_neigh; + int idx = 0; + + hlist_for_each_entry_rcu(hardif_neigh, + &hard_iface->neigh_list, list) { + if (idx++ < *idx_s) + continue; + + if (batadv_iv_ogm_neigh_dump_neigh(msg, portid, seq, + hardif_neigh)) { + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + + *idx_s = 0; + return 0; +} + +static void +batadv_iv_ogm_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *single_hardif) +{ + struct batadv_hard_iface *hard_iface; + int i_hardif = 0; + int i_hardif_s = cb->args[0]; + int idx = cb->args[1]; + int portid = NETLINK_CB(cb->skb).portid; + + rcu_read_lock(); + if (single_hardif) { + if (i_hardif_s == 0) { + if (batadv_iv_ogm_neigh_dump_hardif(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, + single_hardif, + &idx) == 0) + i_hardif++; + } + } else { + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->soft_iface != bat_priv->soft_iface) + continue; + + if (i_hardif++ < i_hardif_s) + continue; + + if (batadv_iv_ogm_neigh_dump_hardif(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, + hard_iface, &idx)) { + i_hardif--; + break; + } + } + } + rcu_read_unlock(); + + cb->args[0] = i_hardif; + cb->args[1] = idx; +} + /** * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors * @neigh1: the first neighbor object of the comparison @@ -2063,7 +2329,9 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = { .bat_neigh_cmp = batadv_iv_ogm_neigh_cmp, .bat_neigh_is_similar_or_better = batadv_iv_ogm_neigh_is_sob, .bat_neigh_print = batadv_iv_neigh_print, + .bat_neigh_dump = batadv_iv_ogm_neigh_dump, .bat_orig_print = batadv_iv_ogm_orig_print, + .bat_orig_dump = batadv_iv_ogm_orig_dump, .bat_orig_free = batadv_iv_ogm_orig_free, .bat_orig_add_if = batadv_iv_ogm_orig_add_if, .bat_orig_del_if = batadv_iv_ogm_orig_del_if,
On Thursday 28 April 2016 22:37:24 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
include/uapi/linux/batman_adv.h | 2 + net/batman-adv/bat_iv_ogm.c | 268 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+)
You can find the missing includes in the attached patch
Kind regards, Sven
From: Matthias Schiffer mschiffer@universe-factory.net
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net --- include/uapi/linux/batman_adv.h | 1 + net/batman-adv/bat_v.c | 250 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index baf4ac8..27f277f 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -78,6 +78,7 @@ enum { BATADV_ATTR_LAST_SEEN_MSECS, BATADV_ATTR_NEIGH_ADDRESS, BATADV_ATTR_TQ, + BATADV_ATTR_THROUGHPUT, __BATADV_ATTR_MAX, };
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 3ff8bd1..1630684 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -29,11 +29,13 @@ #include <linux/seq_file.h> #include <linux/types.h> #include <linux/workqueue.h> +#include <uapi/linux/batman_adv.h>
#include "bat_v_elp.h" #include "bat_v_ogm.h" #include "hard-interface.h" #include "hash.h" +#include "netlink.h" #include "originator.h" #include "packet.h"
@@ -182,6 +184,107 @@ static void batadv_v_neigh_print(struct batadv_priv *bat_priv, seq_puts(seq, "No batman nodes in range ...\n"); }
+static int +batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_hardif_neigh_node *hardif_neigh) +{ + void *hdr; + unsigned int last_seen_msecs; + u32 throughput; + + last_seen_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen); + throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); + throughput = throughput * 100; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_NEIGHBORS); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, + hardif_neigh->addr) || + nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + hardif_neigh->if_incoming->net_dev->ifindex) || + nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, + last_seen_msecs) || + nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_v_neigh_dump_hardif(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface, + int *idx_s) +{ + struct batadv_hardif_neigh_node *hardif_neigh; + int idx = 0; + + hlist_for_each_entry_rcu(hardif_neigh, + &hard_iface->neigh_list, list) { + if (idx++ < *idx_s) + continue; + + if (batadv_v_neigh_dump_neigh(msg, portid, seq, hardif_neigh)) { + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + + *idx_s = 0; + return 0; +} + +static void +batadv_v_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *single_hardif) +{ + struct batadv_hard_iface *hard_iface; + int i_hardif = 0; + int i_hardif_s = cb->args[0]; + int idx = cb->args[1]; + int portid = NETLINK_CB(cb->skb).portid; + + rcu_read_lock(); + if (single_hardif) { + if (i_hardif_s == 0) { + if (batadv_v_neigh_dump_hardif(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, single_hardif, + &idx) == 0) + i_hardif++; + } + } else { + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->soft_iface != bat_priv->soft_iface) + continue; + + if (i_hardif++ < i_hardif_s) + continue; + + if (batadv_v_neigh_dump_hardif(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, hard_iface, + &idx)) { + i_hardif--; + break; + } + } + } + rcu_read_unlock(); + + cb->args[0] = i_hardif; + cb->args[1] = idx; +} + /** * batadv_v_orig_print - print the originator table * @bat_priv: the bat priv with all the soft interface information @@ -249,6 +352,151 @@ next: seq_puts(seq, "No batman nodes in range ...\n"); }
+static int +batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct batadv_orig_node *orig_node, + struct batadv_neigh_node *neigh_node, + bool best) +{ + struct batadv_neigh_ifinfo *n_ifinfo; + unsigned int last_seen_msecs; + u32 throughput; + void *hdr; + + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); + if (!n_ifinfo) + return 0; + + throughput = n_ifinfo->bat_v.throughput * 100; + + batadv_neigh_ifinfo_put(n_ifinfo); + + last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_seen); + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI, + BATADV_CMD_GET_ORIGINATORS); + if (!hdr) + return -ENOBUFS; + + if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) || + nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN, + neigh_node->addr) || + nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, + neigh_node->if_incoming->net_dev->ifindex) || + nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) || + nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, + last_seen_msecs)) + goto nla_put_failure; + + if (best && nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +batadv_v_orig_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct batadv_orig_node *orig_node, int *sub_s) +{ + struct batadv_neigh_node *neigh_node_best; + struct batadv_neigh_node *neigh_node; + int sub = 0; + bool best; + + neigh_node_best = batadv_orig_router_get(orig_node, if_outgoing); + if (!neigh_node_best) + goto out; + + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { + if (sub++ < *sub_s) + continue; + + best = (neigh_node == neigh_node_best); + + if (batadv_v_orig_dump_subentry(msg, portid, seq, bat_priv, + if_outgoing, orig_node, + neigh_node, best)) { + batadv_neigh_node_put(neigh_node_best); + + *sub_s = sub - 1; + return -EMSGSIZE; + } + } + + out: + if (neigh_node_best) + batadv_neigh_node_put(neigh_node_best); + + *sub_s = 0; + return 0; +} + +static int +batadv_v_orig_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing, + struct hlist_head *head, int *idx_s, int *sub) +{ + struct batadv_orig_node *orig_node; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, head, hash_entry) { + if (idx++ < *idx_s) + continue; + + if (batadv_v_orig_dump_entry(msg, portid, seq, bat_priv, + if_outgoing, orig_node, sub)) { + rcu_read_unlock(); + *idx_s = idx - 1; + return -EMSGSIZE; + } + } + rcu_read_unlock(); + + *idx_s = 0; + *sub = 0; + return 0; +} + +static void +batadv_v_orig_dump(struct sk_buff *msg, struct netlink_callback *cb, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_hashtable *hash = bat_priv->orig_hash; + struct hlist_head *head; + int bucket = cb->args[0]; + int idx = cb->args[1]; + int sub = cb->args[2]; + int portid = NETLINK_CB(cb->skb).portid; + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_v_orig_dump_bucket(msg, portid, + cb->nlh->nlmsg_seq, + bat_priv, if_outgoing, head, &idx, + &sub)) + break; + + bucket++; + } + + cb->args[0] = bucket; + cb->args[1] = idx; + cb->args[2] = sub; +} + static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing1, struct batadv_neigh_node *neigh2, @@ -293,9 +541,11 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { .bat_ogm_emit = batadv_v_ogm_emit, .bat_ogm_schedule = batadv_v_ogm_schedule, .bat_orig_print = batadv_v_orig_print, + .bat_orig_dump = batadv_v_orig_dump, .bat_neigh_cmp = batadv_v_neigh_cmp, .bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob, .bat_neigh_print = batadv_v_neigh_print, + .bat_neigh_dump = batadv_v_neigh_dump, };
/**
On Thursday 28 April 2016 22:37:25 Andrew Lunn wrote:
From: Matthias Schiffer mschiffer@universe-factory.net
Signed-off-by: Matthias Schiffer mschiffer@universe-factory.net
include/uapi/linux/batman_adv.h | 1 + net/batman-adv/bat_v.c | 250 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+)
You can find the missing includes in the attached patch
Kind regards, Sven
Set the netnsof flag on the family structure, indicating it can be used with different network name spaces.
Signed-off-by: Andrew Lunn andrew@lunn.ch --- net/batman-adv/netlink.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 3b40eb5..120e6cc 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -33,6 +33,7 @@ struct genl_family batadv_netlink_family = { .name = BATADV_NL_NAME, .version = 1, .maxattr = BATADV_ATTR_MAX, + .netnsok = true, };
static int
Dump the list of gateways via the netlink socket.
Signed-off-by: Andrew Lunn andrew@lunn.ch --- include/uapi/linux/batman_adv.h | 4 ++ net/batman-adv/gateway_client.c | 126 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/gateway_client.h | 1 + net/batman-adv/netlink.c | 7 +++ 4 files changed, 138 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 27f277f..cce4955 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -79,6 +79,9 @@ enum { BATADV_ATTR_NEIGH_ADDRESS, BATADV_ATTR_TQ, BATADV_ATTR_THROUGHPUT, + BATADV_ATTR_BANDWIDTH_UP, + BATADV_ATTR_BANDWIDTH_DOWN, + BATADV_ATTR_ROUTER, __BATADV_ATTR_MAX, };
@@ -93,6 +96,7 @@ enum { BATADV_CMD_GET_TRANSTABLE_GLOBAL, BATADV_CMD_GET_ORIGINATORS, BATADV_CMD_GET_NEIGHBORS, + BATADV_CMD_GET_GATEWAYS, __BATADV_CMD_MAX, };
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 5839c56..4e8525d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -39,12 +39,15 @@ #include <linux/spinlock.h> #include <linux/stddef.h> #include <linux/udp.h> +#include <uapi/linux/batman_adv.h>
#include "gateway_common.h" #include "hard-interface.h" +#include "netlink.h" #include "originator.h" #include "packet.h" #include "routing.h" +#include "soft-interface.h" #include "sysfs.h" #include "translation-table.h"
@@ -662,6 +665,129 @@ out: return 0; }
+static int +batadv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_priv *bat_priv, + struct batadv_gw_node *gw_node) +{ + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; + int ret = -EINVAL; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); + if (!router) + goto out; + + router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); + if (!router_ifinfo) + goto out; + + curr_gw = batadv_gw_get_selected_gw_node(bat_priv); + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, + NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS); + if (!hdr) { + ret = -ENOBUFS; + goto out; + } + + ret = -EMSGSIZE; + + if (curr_gw == gw_node) + if (nla_put_flag(msg, BATADV_ATTR_FLAG_BEST)) { + genlmsg_cancel(msg, hdr); + goto out; + } + + if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, + gw_node->orig_node->orig) || + nla_put_u8(msg, BATADV_ATTR_TQ, router_ifinfo->bat_iv.tq_avg) || + nla_put(msg, BATADV_ATTR_ROUTER, ETH_ALEN, + router->addr) || + nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, + router->if_incoming->net_dev->name) || + nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN, + gw_node->bandwidth_down) || + nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP, + gw_node->bandwidth_up)) { + genlmsg_cancel(msg, hdr); + goto out; + } + + genlmsg_end(msg, hdr); + ret = 0; + +out: + if (router_ifinfo) + batadv_neigh_ifinfo_put(router_ifinfo); + if (router) + batadv_neigh_node_put(router); + return ret; +} + +int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct batadv_hard_iface *primary_if = NULL; + struct net *net = sock_net(cb->skb->sk); + int portid = NETLINK_CB(cb->skb).portid; + struct net_device *soft_iface = NULL; + struct batadv_gw_node *gw_node; + struct batadv_priv *bat_priv; + int idx_skip = cb->args[0]; + int ifindex; + int idx = 0; + int ret; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + rcu_read_lock(); + hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { + if (idx++ < idx_skip) + continue; + + if (batadv_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq, + bat_priv, gw_node)) { + idx_skip = idx - 1; + ret = msg->len; + goto unlock; + } + } + + idx_skip = idx; + ret = msg->len; +unlock: + rcu_read_unlock(); + +out: + if (primary_if) + batadv_hardif_put(primary_if); + if (soft_iface) + dev_put(soft_iface); + + cb->args[0] = idx_skip; + + return ret; +} + /** * batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message * @skb: the packet to check diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 582dd8c..294ff09 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -40,6 +40,7 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); void batadv_gw_node_free(struct batadv_priv *bat_priv); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); +int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb); bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); enum batadv_dhcp_recipient batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 120e6cc..5563028 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -22,6 +22,7 @@ #include <net/sock.h> #include <uapi/linux/batman_adv.h>
+#include "gateway_client.h" #include "hard-interface.h" #include "originator.h" #include "soft-interface.h" @@ -259,6 +260,12 @@ static struct genl_ops batadv_netlink_ops[] = { .policy = batadv_netlink_policy, .dumpit = batadv_hardif_neigh_dump, }, + { + .cmd = BATADV_CMD_GET_GATEWAYS, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_gw_dump, + }, };
void __init batadv_netlink_register(void)
On Thursday 28 April 2016 22:37:27 Andrew Lunn wrote:
Dump the list of gateways via the netlink socket.
Signed-off-by: Andrew Lunn andrew@lunn.ch
include/uapi/linux/batman_adv.h | 4 ++ net/batman-adv/gateway_client.c | 126 ++++++++++++++++++++++++++++++++++++++++ net/batman-adv/gateway_client.h | 1 + net/batman-adv/netlink.c | 7 +++ 4 files changed, 138 insertions(+)
You can find the missing includes in the attached patch
Kind regards, Sven
On Friday 29 April 2016 21:15:20 Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:27 Andrew Lunn wrote:
Dump the list of gateways via the netlink socket.
Signed-off-by: Andrew Lunn andrew@lunn.ch
include/uapi/linux/batman_adv.h | 4 ++ net/batman-adv/gateway_client.c | 126
++++++++++++++++++++++++++++++++++++++++ net/batman-adv/gateway_client.h |
1 + net/batman-adv/netlink.c | 7 +++ 4 files changed, 138 insertions(+)
You can find the missing includes in the attached patch
There were more missing in gateway_client.c. See attached patch
Kind regards, Sven
Dump the list of bridge loop avoidance claims via the netlink socket.
Signed-off-by: Andrew Lunn andrew@lunn.ch --- include/uapi/linux/batman_adv.h | 6 ++ net/batman-adv/bridge_loop_avoidance.c | 162 +++++++++++++++++++++++++++++++++ net/batman-adv/bridge_loop_avoidance.h | 9 +- net/batman-adv/netlink.c | 7 ++ 4 files changed, 183 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index cce4955..6a97a2c 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -82,6 +82,11 @@ enum { BATADV_ATTR_BANDWIDTH_UP, BATADV_ATTR_BANDWIDTH_DOWN, BATADV_ATTR_ROUTER, + BATADV_ATTR_BLA_OWN, + BATADV_ATTR_BLA_ADDRESS, + BATADV_ATTR_BLA_VID, + BATADV_ATTR_BLA_BACKBONE, + BATADV_ATTR_BLA_CRC, __BATADV_ATTR_MAX, };
@@ -97,6 +102,7 @@ enum { BATADV_CMD_GET_ORIGINATORS, BATADV_CMD_GET_NEIGHBORS, BATADV_CMD_GET_GATEWAYS, + BATADV_CMD_GET_BLA_CLAIM, __BATADV_CMD_MAX, };
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 748a9ea..b3fab2a 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -45,11 +45,15 @@ #include <linux/string.h> #include <linux/workqueue.h> #include <net/arp.h> +#include <net/sock.h> +#include <uapi/linux/batman_adv.h>
#include "hard-interface.h" #include "hash.h" +#include "netlink.h" #include "originator.h" #include "packet.h" +#include "soft-interface.h" #include "sysfs.h" #include "translation-table.h"
@@ -1983,6 +1987,164 @@ out: }
/** + * batadv_bla_claim_dump_entry - dump one entry of the backbone table + * to a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @primary_if: primary interface + * @claim: entry to dump + * + * Return: 0 or error code. + */ +static int +batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_hard_iface *primary_if, + struct batadv_bla_claim *claim) +{ + u8 *primary_addr = primary_if->net_dev->dev_addr; + u16 backbone_crc; + bool is_own; + void *hdr; + int ret = -EINVAL; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, + NLM_F_MULTI, BATADV_CMD_GET_BLA_CLAIM); + if (!hdr) { + ret = -ENOBUFS; + goto out; + } + + is_own = batadv_compare_eth(claim->backbone_gw->orig, + primary_addr); + + spin_lock_bh(&claim->backbone_gw->crc_lock); + backbone_crc = claim->backbone_gw->crc; + spin_unlock_bh(&claim->backbone_gw->crc_lock); + + if (is_own) + if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) { + genlmsg_cancel(msg, hdr); + goto out; + } + + if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) || + nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) || + nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN, + claim->backbone_gw->orig) || + nla_put_u16(msg, BATADV_ATTR_BLA_CRC, + backbone_crc)) { + genlmsg_cancel(msg, hdr); + goto out; + } + + genlmsg_end(msg, hdr); + ret = 0; + +out: + return ret; +} + +/** + * batadv_bla_claim_dump_bucket - dump one bucket of the backbone table + * to a netlink socket + * @msg: buffer for the message + * @portid: netlink port + * @seq: Sequence number of netlink message + * @primary_if: primary interface + * @head: bucket to dump + * @idx_skip: How many entries to skip + * + * Return: always 0. + */ +static int +batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_hard_iface *primary_if, + struct hlist_head *head, int *idx_skip) +{ + struct batadv_bla_claim *claim; + int idx = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { + if (idx++ < *idx_skip) + continue; + if (batadv_bla_claim_dump_entry(msg, portid, seq, + primary_if, claim)) + *idx_skip = idx - 1; + goto unlock; + } + + *idx_skip = idx; +unlock: + rcu_read_unlock(); + return 0; +} + +/** + * batadv_bla_claim_dump - dump backbone table to a netlink socket + * @msg: buffer for the message + * @cb: callback structure containing arguments + * + * Return: message length. + */ +int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct batadv_hard_iface *primary_if = NULL; + int portid = NETLINK_CB(cb->skb).portid; + struct net *net = sock_net(cb->skb->sk); + struct net_device *soft_iface = NULL; + struct batadv_hashtable *hash; + struct batadv_priv *bat_priv; + int bucket = cb->args[0]; + struct hlist_head *head; + int idx = cb->args[1]; + int ifindex; + int ret; + + ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return -EINVAL; + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { + ret = -ENODEV; + goto out; + } + + bat_priv = netdev_priv(soft_iface); + hash = bat_priv->bla.claim_hash; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { + ret = -ENOENT; + goto out; + } + + while (bucket < hash->size) { + head = &hash->table[bucket]; + + if (batadv_bla_claim_dump_bucket(msg, portid, + cb->nlh->nlmsg_seq, + primary_if, head, &idx)) + break; + bucket++; + } + + cb->args[0] = bucket; + cb->args[1] = idx; + + ret = msg->len; + +out: + if (primary_if) + batadv_hardif_put(primary_if); + + return 0; +} + +/** * batadv_bla_backbone_table_seq_print_text - print the backbone table in a seq * file * @seq: seq file to print on diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 0f01dae..2d6acfd 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h @@ -35,6 +35,7 @@ bool batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_orig_node *orig_node, int hdr_size); int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); +int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset); bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, @@ -47,7 +48,7 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, void batadv_bla_status_update(struct net_device *net_dev); int batadv_bla_init(struct batadv_priv *bat_priv); void batadv_bla_free(struct batadv_priv *bat_priv); - +int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb); #define BATADV_BLA_CRC_INIT 0 #else /* ifdef CONFIG_BATMAN_ADV_BLA */
@@ -112,6 +113,12 @@ static inline void batadv_bla_free(struct batadv_priv *bat_priv) { }
+static inline int batadv_bla_claim_dump(struct sk_buff *msg, + struct netlink_callback *cb) +{ + return -EOPNOTSUPP; +} + #endif /* ifdef CONFIG_BATMAN_ADV_BLA */
#endif /* ifndef _NET_BATMAN_ADV_BLA_H_ */ diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 5563028..be66a84 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -22,6 +22,7 @@ #include <net/sock.h> #include <uapi/linux/batman_adv.h>
+#include "bridge_loop_avoidance.h" #include "gateway_client.h" #include "hard-interface.h" #include "originator.h" @@ -266,6 +267,12 @@ static struct genl_ops batadv_netlink_ops[] = { .policy = batadv_netlink_policy, .dumpit = batadv_gw_dump, }, + { + .cmd = BATADV_CMD_GET_BLA_CLAIM, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .dumpit = batadv_bla_claim_dump, + }, };
void __init batadv_netlink_register(void)
On Thursday 28 April 2016 22:37:28 Andrew Lunn wrote:
Dump the list of bridge loop avoidance claims via the netlink socket.
Signed-off-by: Andrew Lunn andrew@lunn.ch
include/uapi/linux/batman_adv.h | 6 ++ net/batman-adv/bridge_loop_avoidance.c | 162 +++++++++++++++++++++++++++++++++ net/batman-adv/bridge_loop_avoidance.h | 9 +- net/batman-adv/netlink.c | 7 ++ 4 files changed, 183 insertions(+), 1 deletion(-)
You can find the missing includes in the attached patch
Kind regards, Sven
On Thursday 28 April 2016 22:37:28 Andrew Lunn wrote:
hlist_for_each_entry_rcu(claim, head, hash_entry) {
if (idx++ < *idx_skip)
continue;
if (batadv_bla_claim_dump_entry(msg, portid, seq,
primary_if, claim))
*idx_skip = idx - 1;
goto unlock;
}
This is buggy and will always jump to unlock after the first entry. Please enclose the "*idx_skip = idx - 1;" and "goto unlock;" with { ... }
Kind regards, Sven
On Fri, Apr 29, 2016 at 11:07:37PM +0200, Sven Eckelmann wrote:
On Thursday 28 April 2016 22:37:28 Andrew Lunn wrote:
hlist_for_each_entry_rcu(claim, head, hash_entry) {
if (idx++ < *idx_skip)
continue;
if (batadv_bla_claim_dump_entry(msg, portid, seq,
primary_if, claim))
*idx_skip = idx - 1;
goto unlock;
}
This is buggy and will always jump to unlock after the first entry. Please enclose the "*idx_skip = idx - 1;" and "goto unlock;" with { ... }
Hi Sven
Yep. As i said, untested and likely broken.
I will fix this, and it would be good if somebody could test the v2, and maybe even fix it. Or i can drop this patch.
Andrew
On Thu, Apr 28, 2016 at 10:37:18PM +0200, Andrew Lunn wrote:
This patchset completes netns support, by disabling debugfs entries when not in the default name space, and correctly handling interface stack loops when the parent is in a different name space.
It additionally adds netlink support for most of the information found in debugfs, and is netns awaire.
Note: BLA is untested, so best assume it is broken...
I forgot to add, no attempt has been made to compile this on older kernels. So it probably does not...
Andrew
On Thursday 28 April 2016 22:46:10 Andrew Lunn wrote:
On Thu, Apr 28, 2016 at 10:37:18PM +0200, Andrew Lunn wrote:
This patchset completes netns support, by disabling debugfs entries when not in the default name space, and correctly handling interface stack loops when the parent is in a different name space.
It additionally adds netlink support for most of the information found in debugfs, and is netns awaire.
Note: BLA is untested, so best assume it is broken...
I forgot to add, no attempt has been made to compile this on older kernels. So it probably does not...
It doesn't compile in some configurations. There are also some other problems. See the attached mail.
Kind regards, Sven
b.a.t.m.a.n@lists.open-mesh.org