Hi,
Jiri Pirko called the batman-adv configuration interface a while back "a huge mistake" [1] and suggested genl as alternative. The first reimplementation [2] (based on the team/devlink design) was rejected. This second implementation is now using a nl80211-like design. The objects which can now be modified/queried are:
* mesh/soft-interface (BATADV_CMD_GET_MESH/BATADV_CMD_SET_MESH) * slave/hard-interface (BATADV_CMD_GET_HARDIF/BATADV_CMD_SET_HARDIF) * vlan (BATADV_CMD_GET_VLAN/BATADV_CMD_SET_VLAN)
Such a set messages automatically triggers a *_SET_* "reply" via the config multicast group. The same behavior was also added to the sysfs interface.
I would like to ask the other developers to check whether their configuration values are represented correctly. And please also check whether the current implementation might collide with some other features which you might have in your pipeline.
v3: * correctly assign kernel-doc for BATADV_GW_MODE_CLIENT * fix validation check for gw.sel_class * fix setting of BATADV_ATTR_ORIG_INTERVAL * Cc the (most likely) responsible developers for each setting to more directly ask them for feedback v2: * rewrite everything in a more nl80211-like message/attribute format.
Kind regards, Sven
[1] https://www.open-mesh.org/issues/300 [2] https://patchwork.open-mesh.org/cover/17610/
Sven Eckelmann (19): batman-adv: Move common genl doit code pre/post hooks batman-adv: Prepare framework for mesh genl config batman-adv: Prepare framework for hardif genl config batman-adv: Prepare framework for vlan genl config batman-adv: Add aggregated_ogms mesh genl configuration batman-adv: Add ap_isolation mesh/vlan genl configuration batman-adv: Add bonding mesh genl configuration batman-adv: Add bridge_loop_avoidance mesh genl configuration batman-adv: Add distributed_arp_table mesh genl configuration batman-adv: Add fragmentation mesh genl configuration batman-adv: Add gateway mesh genl configuration batman-adv: Add hop_penalty mesh genl configuration batman-adv: Add log_level mesh genl configuration batman-adv: Add multicast_mode mesh genl configuration batman-adv: Add network_coding mesh genl configuration batman-adv: Add orig_interval mesh genl configuration batman-adv: Add elp_interval hardif genl configuration batman-adv: Add throughput_override hardif genl configuration batman-adv: Trigger genl notification on sysfs config change
include/uapi/linux/batman_adv.h | 188 +++++- net/batman-adv/gateway_client.c | 1 - net/batman-adv/gateway_common.c | 1 + net/batman-adv/gateway_common.h | 6 - net/batman-adv/netlink.c | 1074 +++++++++++++++++++++++++++---- net/batman-adv/netlink.h | 6 + net/batman-adv/soft-interface.c | 2 +- net/batman-adv/sysfs.c | 64 +- 8 files changed, 1195 insertions(+), 147 deletions(-)
The commit ff4c92d85c6f ("genetlink: introduce pre_doit/post_doit hooks") intoduced a mechanism to run specific code for doit hooks before/after the hooks are run. Since all doit hooks are requiring the batadv softif, it should be retrieved/freed in these helpers to simplify the code.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/netlink.c | 140 +++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 43 deletions(-)
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 2dc3304c..b20801a3 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -20,8 +20,10 @@ #include "main.h"
#include <linux/atomic.h> +#include <linux/bitops.h> #include <linux/byteorder/generic.h> #include <linux/cache.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/export.h> #include <linux/genetlink.h> @@ -54,6 +56,8 @@ #include "tp_meter.h" #include "translation-table.h"
+struct net; + struct genl_family batadv_netlink_family;
/* multicast groups */ @@ -61,6 +65,18 @@ enum batadv_netlink_multicast_groups { BATADV_NL_MCGRP_TPMETER, };
+/** + * enum batadv_genl_ops_flags - flags for genl_ops's internal_flags + */ +enum batadv_genl_ops_flags { + /** + * @BATADV_FLAG_NEED_MESH: request requires valid soft interface in + * attribute BATADV_ATTR_MESH_IFINDEX and expects a pointer to it to be + * safed in info->user_ptr[0] + */ + BATADV_FLAG_NEED_MESH = BIT(0), +}; + static const struct genl_multicast_group batadv_netlink_mcgrps[] = { [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER }, }; @@ -329,40 +345,24 @@ int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst, static int batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info) { - struct net *net = genl_info_net(info); - struct net_device *soft_iface; - struct batadv_priv *bat_priv; + struct batadv_priv *bat_priv = info->user_ptr[0]; struct sk_buff *msg = NULL; u32 test_length; void *msg_head; - int ifindex; u32 cookie; u8 *dst; int ret;
- if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) - return -EINVAL; - if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) return -EINVAL;
if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]) return -EINVAL;
- ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); - if (!ifindex) - return -EINVAL; - dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]);
- 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; @@ -377,15 +377,11 @@ batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info) goto out; }
- bat_priv = netdev_priv(soft_iface); batadv_tp_start(bat_priv, dst, test_length, &cookie);
ret = batadv_netlink_tp_meter_put(msg, cookie);
out: - if (soft_iface) - dev_put(soft_iface); - if (ret) { if (msg) nlmsg_free(msg); @@ -406,38 +402,17 @@ batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info) static int batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info) { - struct net *net = genl_info_net(info); - struct net_device *soft_iface; - struct batadv_priv *bat_priv; - int ifindex; + struct batadv_priv *bat_priv = info->user_ptr[0]; u8 *dst; int ret = 0;
- if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) - return -EINVAL; - if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) return -EINVAL;
- ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); - if (!ifindex) - return -EINVAL; - dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
- 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); batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL);
-out: - if (soft_iface) - dev_put(soft_iface); - return ret; }
@@ -545,6 +520,81 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) return msg->len; }
+/** + * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes + * @net: the applicable net namespace + * @info: receiver information + * + * Return: Pointer to soft interface on success, error pointer on error + */ +static struct batadv_priv * +batadv_get_softif_from_info(struct net *net, struct genl_info *info) +{ + struct net_device *soft_iface; + int ifindex; + + if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) + return ERR_PTR(-EINVAL); + + ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); + + soft_iface = dev_get_by_index(net, ifindex); + if (!soft_iface) + return ERR_PTR(-ENODEV); + + if (!batadv_softif_is_valid(soft_iface)) + goto err_put_softif; + + return netdev_priv(soft_iface); + +err_put_softif: + dev_put(soft_iface); + + return ERR_PTR(-EINVAL); +} + +/** + * batadv_pre_doit() - Prepare batman-adv genl doit request + * @ops: requested netlink operation + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct batadv_priv *bat_priv; + + if (ops->internal_flags & BATADV_FLAG_NEED_MESH) { + bat_priv = batadv_get_softif_from_info(genl_info_net(info), + info); + if (IS_ERR(bat_priv)) + return PTR_ERR(bat_priv); + + info->user_ptr[0] = bat_priv; + } + + return 0; +} + +/** + * batadv_post_doit() - End batman-adv genl doit request + * @ops: requested netlink operation + * @skb: Netlink message with request data + * @info: receiver information + */ +static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct batadv_priv *bat_priv; + + if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { + bat_priv = info->user_ptr[0]; + dev_put(bat_priv->soft_iface); + } +} + static const struct genl_ops batadv_netlink_ops[] = { { .cmd = BATADV_CMD_GET_MESH_INFO, @@ -557,12 +607,14 @@ static const struct genl_ops batadv_netlink_ops[] = { .flags = GENL_ADMIN_PERM, .policy = batadv_netlink_policy, .doit = batadv_netlink_tp_meter_start, + .internal_flags = BATADV_FLAG_NEED_MESH, }, { .cmd = BATADV_CMD_TP_METER_CANCEL, .flags = GENL_ADMIN_PERM, .policy = batadv_netlink_policy, .doit = batadv_netlink_tp_meter_cancel, + .internal_flags = BATADV_FLAG_NEED_MESH, }, { .cmd = BATADV_CMD_GET_ROUTING_ALGOS, @@ -639,6 +691,8 @@ struct genl_family batadv_netlink_family __ro_after_init = { .version = 1, .maxattr = BATADV_ATTR_MAX, .netnsok = true, + .pre_doit = batadv_pre_doit, + .post_doit = batadv_post_doit, .module = THIS_MODULE, .ops = batadv_netlink_ops, .n_ops = ARRAY_SIZE(batadv_netlink_ops),
On Fri, Dec 07, 2018 at 02:58:28PM +0100, Sven Eckelmann wrote:
+/**
- batadv_get_softif_from_info() - Retrieve soft interface from genl attributes
- @net: the applicable net namespace
- @info: receiver information
- Return: Pointer to soft interface on success, error pointer on error
- */
+static struct batadv_priv * +batadv_get_softif_from_info(struct net *net, struct genl_info *info)
Since this returns a batadv_priv, shouldn't it better be called batadv_get_batpriv_from_info() or batadv_get_bat_priv_from_info() maybe?
+{
- struct net_device *soft_iface;
- int ifindex;
- if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
return ERR_PTR(-EINVAL);
- ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
- soft_iface = dev_get_by_index(net, ifindex);
- if (!soft_iface)
return ERR_PTR(-ENODEV);
- if (!batadv_softif_is_valid(soft_iface))
goto err_put_softif;
- return netdev_priv(soft_iface);
+err_put_softif:
- dev_put(soft_iface);
- return ERR_PTR(-EINVAL);
+}
Is holding a reference to bat_priv->soft_iface really necessary (and releasing it in batadv_post_doit() )? If we are able to retrieve a valid bat_priv then this bat_priv itself should hold a reference to to soft_iface, shouldn't it?
+/**
- batadv_pre_doit() - Prepare batman-adv genl doit request
- @ops: requested netlink operation
- @skb: Netlink message with request data
- @info: receiver information
- Return: 0 on success or negative error number in case of failure
- */
+static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
+{
- struct batadv_priv *bat_priv;
- if (ops->internal_flags & BATADV_FLAG_NEED_MESH) {
bat_priv = batadv_get_softif_from_info(genl_info_net(info),
info);
Would it look nicer to store genl_info_net(info) in a temporary variable so that its shorter and the newline for the second parameter could be avoided?
if (IS_ERR(bat_priv))
return PTR_ERR(bat_priv);
info->user_ptr[0] = bat_priv;
Would it make sense to wrap this private data access into something somehow? Conceptually similar to what we do not with skb private data already for instance. There we use BATADV_SKB_CB() for instance.
- }
- return 0;
+}
On Sunday, 30 December 2018 17.57.54 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:28PM +0100, Sven Eckelmann wrote:
+/**
- batadv_get_softif_from_info() - Retrieve soft interface from genl
attributes
- @net: the applicable net namespace
- @info: receiver information
- Return: Pointer to soft interface on success, error pointer on error
- */
+static struct batadv_priv * +batadv_get_softif_from_info(struct net *net, struct genl_info *info)
Since this returns a batadv_priv, shouldn't it better be called batadv_get_batpriv_from_info() or batadv_get_bat_priv_from_info() maybe?
OK
+{
- struct net_device *soft_iface;
- int ifindex;
- if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
return ERR_PTR(-EINVAL);
- ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
- soft_iface = dev_get_by_index(net, ifindex);
- if (!soft_iface)
return ERR_PTR(-ENODEV);
- if (!batadv_softif_is_valid(soft_iface))
goto err_put_softif;
- return netdev_priv(soft_iface);
+err_put_softif:
- dev_put(soft_iface);
- return ERR_PTR(-EINVAL);
+}
Is holding a reference to bat_priv->soft_iface really necessary (and releasing it in batadv_post_doit() )? If we are able to retrieve a valid bat_priv then this bat_priv itself should hold a reference to to soft_iface, shouldn't it?
No, we don't hold any explicit reference to bat_priv itself. The bat_priv is a part of the memory of the soft_iface. So we most hold a reference for soft_iface because we don't prevent that it is removed in the meantime (the netlink interface is registered per module and not per meshif/softif).
[...]
- if (ops->internal_flags & BATADV_FLAG_NEED_MESH) {
bat_priv = batadv_get_softif_from_info(genl_info_net(info),
info);
Would it look nicer to store genl_info_net(info) in a temporary variable so that its shorter and the newline for the second parameter could be avoided?
Ok
if (IS_ERR(bat_priv))
return PTR_ERR(bat_priv);
info->user_ptr[0] = bat_priv;
Would it make sense to wrap this private data access into something somehow? Conceptually similar to what we do not with skb private data already for instance. There we use BATADV_SKB_CB() for instance.
Please not, we only have two pointers and I definitely don't want to force specific positions (we need three at the moment - but max two per command). You should compare it with the nl80211 code.
Kind regards, Sven
The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested.
The main objects for this configuration is the mesh/soft-interface object. Its actual object in memory already contains most of the available configuration settings. The genl interface reflects this by allowing to get/set it using the mesh specific commands.
The BATADV_CMD_GET_MESH_INFO (or short version BATADV_CMD_GET_MESH) is reused as get command because it already provides the content of other information from the mesh/soft-interface which are not yet configuration specific.
The set command BATADV_CMD_SET_MESH will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_MESH command message type that settings might have been changed and what the current values are.
Signed-off-by: Sven Eckelmann sven@narfation.org --- include/uapi/linux/batman_adv.h | 16 +++- net/batman-adv/netlink.c | 159 +++++++++++++++++++------------- 2 files changed, 110 insertions(+), 65 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 324a0e11..2d6a175e 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -27,6 +27,7 @@
#define BATADV_NL_NAME "batadv"
+#define BATADV_NL_MCAST_GROUP_CONFIG "config" #define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter"
/** @@ -372,10 +373,14 @@ enum batadv_nl_commands { BATADV_CMD_UNSPEC,
/** - * @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv - * device + * @BATADV_CMD_GET_MESH: Get attributes from softif/mesh */ - BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_GET_MESH, + + /** + * @BATADV_CMD_GET_MESH_INFO: Alias for @BATADV_CMD_GET_MESH + */ + BATADV_CMD_GET_MESH_INFO = BATADV_CMD_GET_MESH,
/** * @BATADV_CMD_TP_METER: Start a tp meter session @@ -443,6 +448,11 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_MCAST_FLAGS,
+ /** + * @BATADV_CMD_SET_MESH: Set attributes for softif/mesh + */ + BATADV_CMD_SET_MESH, + /* add new commands above here */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index b20801a3..d89761f8 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -62,6 +62,7 @@ struct genl_family batadv_netlink_family;
/* multicast groups */ enum batadv_netlink_multicast_groups { + BATADV_NL_MCGRP_CONFIG, BATADV_NL_MCGRP_TPMETER, };
@@ -78,6 +79,7 @@ enum batadv_genl_ops_flags { };
static const struct genl_multicast_group batadv_netlink_mcgrps[] = { + [BATADV_NL_MCGRP_CONFIG] = { .name = BATADV_NL_MCAST_GROUP_CONFIG }, [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER }, };
@@ -138,20 +140,29 @@ batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) }
/** - * batadv_netlink_mesh_info_put() - fill in generic information about mesh - * interface - * @msg: netlink message to be sent back - * @soft_iface: interface for which the data should be taken + * batadv_netlink_mesh_put() - Fill message with mesh attributes + * @msg: Netlink message to dump into + * @bat_priv: the bat priv with all the soft interface information + * @cmd: type of message to generate + * @portid: Port making netlink request + * @seq: sequence number for message + * @flags: Additional flags for message * - * Return: 0 on success, < 0 on error + * Return: 0 on success or negative error number in case of failure */ -static int -batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) +static int batadv_netlink_mesh_put(struct sk_buff *msg, + struct batadv_priv *bat_priv, + enum batadv_nl_commands cmd, + u32 portid, u32 seq, int flags) { - struct batadv_priv *bat_priv = netdev_priv(soft_iface); + struct net_device *soft_iface = bat_priv->soft_iface; struct batadv_hard_iface *primary_if = NULL; struct net_device *hard_iface; - int ret = -ENOBUFS; + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); + if (!hdr) + return -ENOBUFS;
if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || nla_put_string(msg, BATADV_ATTR_ALGO_NAME, @@ -162,16 +173,16 @@ batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) soft_iface->dev_addr) || nla_put_u8(msg, BATADV_ATTR_TT_TTVN, (u8)atomic_read(&bat_priv->tt.vn))) - goto out; + goto nla_put_failure;
#ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC, ntohs(bat_priv->bla.claim_dest.group))) - goto out; + goto nla_put_failure; #endif
if (batadv_mcast_mesh_info_put(msg, bat_priv)) - goto out; + goto nla_put_failure;
primary_if = batadv_primary_if_get_selected(bat_priv); if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) { @@ -183,77 +194,94 @@ batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) hard_iface->name) || nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, hard_iface->dev_addr)) - goto out; + goto nla_put_failure; }
- ret = 0; + batadv_hardif_put(primary_if);
- out: + genlmsg_end(msg, hdr); + return 0; + +nla_put_failure: if (primary_if) batadv_hardif_put(primary_if);
- return ret; + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; }
/** - * batadv_netlink_get_mesh_info() - handle incoming BATADV_CMD_GET_MESH_INFO - * netlink request - * @skb: received netlink message - * @info: receiver information + * batadv_netlink_notify_mesh() - send softif attributes to listener + * @bat_priv: the bat priv with all the soft interface information * * Return: 0 on success, < 0 on error */ -static int -batadv_netlink_get_mesh_info(struct sk_buff *skb, struct genl_info *info) +static int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv) { - struct net *net = genl_info_net(info); - struct net_device *soft_iface; - struct sk_buff *msg = NULL; - void *msg_head; - int ifindex; + struct sk_buff *msg; int ret;
- if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) - return -EINVAL; - - ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); - if (!ifindex) - return -EINVAL; + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM;
- soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; + ret = batadv_netlink_mesh_put(msg, bat_priv, BATADV_CMD_SET_MESH, + 0, 0, 0); + if (ret < 0) { + nlmsg_free(msg); + return ret; }
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - ret = -ENOMEM; - goto out; - } + genlmsg_multicast_netns(&batadv_netlink_family, + dev_net(bat_priv->soft_iface), msg, 0, + BATADV_NL_MCGRP_CONFIG, GFP_KERNEL);
- 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; - } + return 0; +}
- ret = batadv_netlink_mesh_info_put(msg, soft_iface); +/** + * batadv_netlink_get_mesh() - Get softif attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_get_mesh(struct sk_buff *skb, struct genl_info *info) +{ + struct batadv_priv *bat_priv = info->user_ptr[0]; + struct sk_buff *msg; + int ret;
- out: - if (soft_iface) - dev_put(soft_iface); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM;
- if (ret) { - if (msg) - nlmsg_free(msg); + ret = batadv_netlink_mesh_put(msg, bat_priv, BATADV_CMD_GET_MESH, + info->snd_portid, info->snd_seq, 0); + if (ret < 0) { + nlmsg_free(msg); return ret; }
- genlmsg_end(msg, msg_head); - return genlmsg_reply(msg, info); + ret = genlmsg_reply(msg, info); + + return ret; +} + +/** + * batadv_netlink_set_mesh() - Set softif attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) +{ + struct batadv_priv *bat_priv = info->user_ptr[0]; + + batadv_netlink_notify_mesh(bat_priv); + + return 0; }
/** @@ -597,10 +625,11 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static const struct genl_ops batadv_netlink_ops[] = { { - .cmd = BATADV_CMD_GET_MESH_INFO, - .flags = GENL_ADMIN_PERM, + .cmd = BATADV_CMD_GET_MESH, + /* can be retrieved by unprivileged users */ .policy = batadv_netlink_policy, - .doit = batadv_netlink_get_mesh_info, + .doit = batadv_netlink_get_mesh, + .internal_flags = BATADV_FLAG_NEED_MESH, }, { .cmd = BATADV_CMD_TP_METER, @@ -682,7 +711,13 @@ static const struct genl_ops batadv_netlink_ops[] = { .policy = batadv_netlink_policy, .dumpit = batadv_mcast_flags_dump, }, - + { + .cmd = BATADV_CMD_SET_MESH, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .doit = batadv_netlink_set_mesh, + .internal_flags = BATADV_FLAG_NEED_MESH, + }, };
struct genl_family batadv_netlink_family __ro_after_init = {
On Fri, Dec 07, 2018 at 02:58:29PM +0100, Sven Eckelmann wrote:
The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested.
The main objects for this configuration is the mesh/soft-interface object. Its actual object in memory already contains most of the available configuration settings. The genl interface reflects this by allowing to get/set it using the mesh specific commands.
The BATADV_CMD_GET_MESH_INFO (or short version BATADV_CMD_GET_MESH) is reused as get command because it already provides the content of other information from the mesh/soft-interface which are not yet configuration specific.
The set command BATADV_CMD_SET_MESH will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_MESH command message type that settings might have been changed and what the current values are.
Signed-off-by: Sven Eckelmann sven@narfation.org
include/uapi/linux/batman_adv.h | 16 +++- net/batman-adv/netlink.c | 159 +++++++++++++++++++------------- 2 files changed, 110 insertions(+), 65 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 324a0e11..2d6a175e 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -27,6 +27,7 @@
#define BATADV_NL_NAME "batadv"
+#define BATADV_NL_MCAST_GROUP_CONFIG "config" #define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter"
/** @@ -372,10 +373,14 @@ enum batadv_nl_commands { BATADV_CMD_UNSPEC,
/**
* @BATADV_CMD_GET_MESH_INFO: Query basic information about batman-adv
* device
*/* @BATADV_CMD_GET_MESH: Get attributes from softif/mesh
- BATADV_CMD_GET_MESH_INFO,
BATADV_CMD_GET_MESH,
/**
* @BATADV_CMD_GET_MESH_INFO: Alias for @BATADV_CMD_GET_MESH
*/
BATADV_CMD_GET_MESH_INFO = BATADV_CMD_GET_MESH,
/**
- @BATADV_CMD_TP_METER: Start a tp meter session
@@ -443,6 +448,11 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_MCAST_FLAGS,
/**
* @BATADV_CMD_SET_MESH: Set attributes for softif/mesh
*/
BATADV_CMD_SET_MESH,
/* add new commands above here */
/**
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index b20801a3..d89761f8 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -62,6 +62,7 @@ struct genl_family batadv_netlink_family;
/* multicast groups */ enum batadv_netlink_multicast_groups {
- BATADV_NL_MCGRP_CONFIG, BATADV_NL_MCGRP_TPMETER,
};
@@ -78,6 +79,7 @@ enum batadv_genl_ops_flags { };
static const struct genl_multicast_group batadv_netlink_mcgrps[] = {
- [BATADV_NL_MCGRP_CONFIG] = { .name = BATADV_NL_MCAST_GROUP_CONFIG }, [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER },
};
@@ -138,20 +140,29 @@ batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) }
/**
- batadv_netlink_mesh_info_put() - fill in generic information about mesh
- interface
- @msg: netlink message to be sent back
- @soft_iface: interface for which the data should be taken
- batadv_netlink_mesh_put() - Fill message with mesh attributes
- @msg: Netlink message to dump into
- @bat_priv: the bat priv with all the soft interface information
- @cmd: type of message to generate
- @portid: Port making netlink request
- @seq: sequence number for message
- @flags: Additional flags for message
- Return: 0 on success, < 0 on error
*/
- Return: 0 on success or negative error number in case of failure
-static int -batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) +static int batadv_netlink_mesh_put(struct sk_buff *msg,
struct batadv_priv *bat_priv,
enum batadv_nl_commands cmd,
u32 portid, u32 seq, int flags)
{
[...]
#ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC, ntohs(bat_priv->bla.claim_dest.group)))
goto out;
goto nla_put_failure;
#endif
if (batadv_mcast_mesh_info_put(msg, bat_priv))
goto out;
goto nla_put_failure;
With the rename of "batadv_netlink_mesh_info_put" to "batadv_netlink_mesh_put", I'm wondering whether batadv_mcast_mesh_info_put() should be renamed, too. batadv_mcast_mesh_put() would probably be a bit too generic. But maybe something like batadv_mcast_nl_mesh_put()?
+/**
- batadv_netlink_get_mesh() - Get softif attributes
- @skb: Netlink message with request data
- @info: receiver information
- Return: 0 on success or negative error number in case of failure
- */
+static int batadv_netlink_get_mesh(struct sk_buff *skb, struct genl_info *info) +{
- struct batadv_priv *bat_priv = info->user_ptr[0];
- struct sk_buff *msg;
- int ret;
Same question here for info->user_ptr[0], would a wrapper make sense?
On Monday, 31 December 2018 12.09.50 CET Linus Lüssing wrote: [...]
[...]
#ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC, ntohs(bat_priv->bla.claim_dest.group)))
goto out;
goto nla_put_failure;
#endif
if (batadv_mcast_mesh_info_put(msg, bat_priv))
goto out;
goto nla_put_failure;
With the rename of "batadv_netlink_mesh_info_put" to "batadv_netlink_mesh_put", I'm wondering whether batadv_mcast_mesh_info_put() should be renamed, too. batadv_mcast_mesh_put() would probably be a bit too generic. But maybe something like batadv_mcast_nl_mesh_put()?
Not relevant for this patch. But feel free to check what we can do to make it more consistent. We can then do it after having the rest in place.
Kind regards, Sven
On Fri, Dec 07, 2018 at 02:58:29PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index b20801a3..d89761f8 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c
[...]
-static int -batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) +static int batadv_netlink_mesh_put(struct sk_buff *msg,
struct batadv_priv *bat_priv,
enum batadv_nl_commands cmd,
u32 portid, u32 seq, int flags)
{
- struct batadv_priv *bat_priv = netdev_priv(soft_iface);
- struct net_device *soft_iface = bat_priv->soft_iface; struct batadv_hard_iface *primary_if = NULL; struct net_device *hard_iface;
- int ret = -ENOBUFS;
void *hdr;
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd);
if (!hdr)
return -ENOBUFS;
if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || nla_put_string(msg, BATADV_ATTR_ALGO_NAME,
@@ -162,16 +173,16 @@ batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) soft_iface->dev_addr) || nla_put_u8(msg, BATADV_ATTR_TT_TTVN, (u8)atomic_read(&bat_priv->tt.vn)))
goto out;
goto nla_put_failure;
#ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC, ntohs(bat_priv->bla.claim_dest.group)))
goto out;
goto nla_put_failure;
#endif
if (batadv_mcast_mesh_info_put(msg, bat_priv))
goto out;
goto nla_put_failure;
primary_if = batadv_primary_if_get_selected(bat_priv); if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) {
@@ -183,77 +194,94 @@ batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) hard_iface->name) || nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, hard_iface->dev_addr))
goto out;
}goto nla_put_failure;
- ret = 0;
- batadv_hardif_put(primary_if);
I seem to be able to trigger a null pointer dereference for this batadv_hardif_put() call here. With the following steps I end up with a primary_if == NULL:
$ batctl if add 1
root@Linus-Debian:~# batctl o Error - interface bat0 is not present or not a batman-adv interface root@Linus-Debian:~# batctl if add 1 Error - interface does not exist: 1 root@Linus-Debian:~# batctl o Killed root@Linus-Debian:~# root@Linus-Debian:~# root@Linus-Debian:~# batctl o
- out:
- genlmsg_end(msg, hdr);
- return 0;
+nla_put_failure: if (primary_if) batadv_hardif_put(primary_if);
- return ret;
- genlmsg_cancel(msg, hdr);
- return -EMSGSIZE;
}
The panic looks like this then:
[ 2309.363754] batman_adv: bat0: Interface deactivated: ens3 [ 2309.364709] batman_adv: bat0: Removing interface: ens3 [ 2309.365662] batman_adv: bat0: Interface deactivated: ens5 [ 2309.366624] batman_adv: bat0: Removing interface: ens5 [ 2310.402540] batman_adv: B.A.T.M.A.N. advanced 2018.4-38-g25676ce7-dirty (compatibility version 15) loaded [ 2321.727530] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028 [ 2321.728869] IP: [<ffffffffc091df19>] batadv_netlink_mesh_put.constprop.13+0x459/0x630 [batman_adv] [ 2321.730060] PGD 0 [ 2321.730311] [ 2321.730533] Oops: 0002 [#1] SMP [ 2321.730952] Modules linked in: batman_adv(O) cfg80211 rfkill evdev joydev serio_raw pcspkr button nfsd bridge auth_rpcgss oid_registry stp nfs_acl lockd llc grace sunrpc crc16 ip_tables x_tables autofs4 btrfs raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c crc32c_generic raid1 raid0 multipath linear md_mod dm_mirror dm_region_hash dm_log dm_mod 9pnet_rdma rdma_cm configfs iw_cm ib_cm ib_core 9p fscache 8139too ata_generic 9pnet_virtio 9pnet psmouse floppy virtio_pci virtio_ring virtio 8139cp mii ata_piix e1000 i2c_piix4 libata scsi_mod [last unloaded: batman_adv] [ 2321.731472] CPU: 0 PID: 2948 Comm: batctl Tainted: G O 4.9.0-7-amd64 #1 Debian 4.9.110-3+deb9u2 [ 2321.731472] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 [ 2321.731472] task: ffff9fa5d9cde100 task.stack: ffffc0d7805e8000 [ 2321.731472] RIP: 0010:[<ffffffffc091df19>] [<ffffffffc091df19>] batadv_netlink_mesh_put.constprop.13+0x459/0x630 [batman_adv] [ 2321.731472] RSP: 0018:ffffc0d7805ebae0 EFLAGS: 00010282 [ 2321.731472] RAX: 0000000000000000 RBX: ffff9fa5dcf4c800 RCX: 00000000000003e8 [ 2321.731472] RDX: ffffffffc091a010 RSI: ffffc0d7805ebaec RDI: ffff9fa5db9c80f8 [ 2321.731472] RBP: ffff9fa5d9d538c0 R08: 00000000000003e8 R09: 0000000000000004 [ 2321.731472] R10: ffff9fa5db9c80fc R11: 0079747269642d37 R12: ffff9fa5db9c8014 [ 2321.731472] R13: 0000000000000028 R14: 0000000000000000 R15: ffffffff8bedbe00 [ 2321.731472] FS: 00007fa18cf5a740(0000) GS:ffff9fa5de800000(0000) knlGS:0000000000000000 [ 2321.731472] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2321.731472] CR2: 0000000000000028 CR3: 0000000018d9f000 CR4: 00000000000006f0 [ 2321.731472] Stack: [ 2321.731472] ffffffff8b6f6cb6 000003e88b6f5d3e 7c37bd74f749c6fc ffffc0d7805ebb90 [ 2321.731472] ffff9fa5dcf4c800 ffff9fa5d9d538c0 ffff9fa5dfa6e500 ffff9fa5db925c00 [ 2321.731472] ffffffff8bedbe00 ffffffffc091e138 ffffffffc092d180 ffffffffc092d180 [ 2321.731472] Call Trace: [ 2321.731472] [<ffffffff8b6f6cb6>] ? __alloc_skb+0x96/0x1e0 [ 2321.731472] [<ffffffffc091e138>] ? batadv_netlink_get_mesh+0x48/0xa0 [batman_adv] [ 2321.731472] [<ffffffff8b7445f5>] ? genl_family_rcv_msg+0x1c5/0x360 [ 2321.731472] [<ffffffff8b6f5d3e>] ? __kmalloc_reserve.isra.35+0x2e/0x80 [ 2321.731472] [<ffffffff8b3e4906>] ? kmem_cache_alloc_node_trace+0x156/0x5a0 [ 2321.731472] [<ffffffff8b744790>] ? genl_family_rcv_msg+0x360/0x360 [ 2321.731472] [<ffffffff8b744812>] ? genl_rcv_msg+0x82/0xc0 [ 2321.731472] [<ffffffff8b743d94>] ? netlink_rcv_skb+0xa4/0xc0 [ 2321.731472] [<ffffffff8b744414>] ? genl_rcv+0x24/0x40 [ 2321.731472] [<ffffffff8b74376a>] ? netlink_unicast+0x18a/0x230 [ 2321.731472] [<ffffffff8b743b67>] ? netlink_sendmsg+0x357/0x3b0 [ 2321.731472] [<ffffffff8b6ee946>] ? sock_sendmsg+0x36/0x40 [ 2321.731472] [<ffffffff8b6ef3d8>] ? ___sys_sendmsg+0x2c8/0x2e0 [ 2321.731472] [<ffffffff8b3fe078>] ? mem_cgroup_commit_charge+0x78/0x4b0 [ 2321.731472] [<ffffffff8b3b8a6e>] ? handle_mm_fault+0xe7e/0x1280 [ 2321.731472] [<ffffffff8b6ed905>] ? move_addr_to_user+0xb5/0xd0 [ 2321.731472] [<ffffffff8b6efce1>] ? __sys_sendmsg+0x51/0x90 [ 2321.731472] [<ffffffff8b203b7d>] ? do_syscall_64+0x8d/0xf0 [ 2321.731472] [<ffffffff8b814c4e>] ? entry_SYSCALL_64_after_swapgs+0x58/0xc6 [ 2321.731472] Code: 00 00 be 39 00 00 00 48 89 df 89 44 24 0c e8 3f 03 c4 ca 85 c0 75 48 48 c7 c2 10 a0 91 c0 49 83 c5 28 48 85 d2 0f 84 ae 01 00 00 <f0> 41 83 6d 00 01 75 10 4c 89 ef 89 44 24 04 e8 e3 c0 ff ff 8b [ 2321.731472] RIP [<ffffffffc091df19>] batadv_netlink_mesh_put.constprop.13+0x459/0x630 [batman_adv] [ 2321.731472] RSP <ffffc0d7805ebae0> [ 2321.731472] CR2: 0000000000000028 [ 2321.770447] ---[ end trace cdc14a8e37e47f7e ]---
Next to a missing bailout for a primary_if == NULL, it's also odd that this "batctl if add" does seem to change something in the kernel even though it returns an error. I haven't looked into why that happens yet, though.
PS: In these tests I had also commented out all items in the *_attrs[] arrays in sysfs.c to make sure that I'm using netlink for everything.
On Monday, 7 January 2019 19.49.06 CET Linus Lüssing wrote: [...]
I seem to be able to trigger a null pointer dereference for this batadv_hardif_put() call here. With the following steps I end up with a primary_if == NULL:
$ batctl if add 1
root@Linus-Debian:~# batctl o Error - interface bat0 is not present or not a batman-adv interface root@Linus-Debian:~# batctl if add 1 Error - interface does not exist: 1 root@Linus-Debian:~# batctl o Killed root@Linus-Debian:~# root@Linus-Debian:~# root@Linus-Debian:~# batctl o
You can reproduce it easier with (destroy is only there to make sure that the bat0 is really empty before the originator dump):
batctl if destroy batctl if create batctl o
The check before
batadv_hardif_put(primary_if);
is missing. So it should actually be (like in the nla_put_failure case):
if (primary_if) batadv_hardif_put(primary_if);
And "batctl if add" is basically a short version of:
batctl if create batctl if add -M XXXX
And in your test, only the second part failed.
Kind regards, Sven
The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested.
Beside the mesh/soft-interface specific configuration, the slave/hard-interface have B.A.T.M.A.N. V specific configuration settings. The genl interface reflects this by allowing to get/set it using the hard-interface specific commands.
The BATADV_CMD_GET_HARDIFS (or short version BATADV_CMD_GET_HARDIF) is reused as get command because it already allow to dump the content of other information from the slave/hard-interface which are not yet configuration specific.
The set command BATADV_CMD_SET_HARDIF will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_HARDIF command message type that settings might have been changed and what the current values are.
Signed-off-by: Sven Eckelmann sven@narfation.org --- include/uapi/linux/batman_adv.h | 16 ++- net/batman-adv/netlink.c | 237 +++++++++++++++++++++++++++++--- 2 files changed, 230 insertions(+), 23 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 2d6a175e..eb5097df 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -398,9 +398,15 @@ enum batadv_nl_commands { BATADV_CMD_GET_ROUTING_ALGOS,
/** - * @BATADV_CMD_GET_HARDIFS: Query list of hard interfaces + * @BATADV_CMD_GET_HARDIF: Get attributes from a hardif of the + * current softif */ - BATADV_CMD_GET_HARDIFS, + BATADV_CMD_GET_HARDIF, + + /** + * @BATADV_CMD_GET_HARDIFS: Alias for @BATADV_CMD_GET_HARDIF + */ + BATADV_CMD_GET_HARDIFS = BATADV_CMD_GET_HARDIF,
/** * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations @@ -453,6 +459,12 @@ enum batadv_nl_commands { */ BATADV_CMD_SET_MESH,
+ /** + * @BATADV_CMD_SET_HARDIF: Set attributes for hardif of the + * current softif + */ + BATADV_CMD_SET_HARDIF, + /* add new commands above here */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index d89761f8..68116eb8 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -21,6 +21,7 @@
#include <linux/atomic.h> #include <linux/bitops.h> +#include <linux/bug.h> #include <linux/byteorder/generic.h> #include <linux/cache.h> #include <linux/err.h> @@ -76,6 +77,13 @@ enum batadv_genl_ops_flags { * safed in info->user_ptr[0] */ BATADV_FLAG_NEED_MESH = BIT(0), + + /** + * @BATADV_FLAG_NEED_HARDIF: request requires valid hard interface in + * attribute BATADV_ATTR_HARD_IFINDEX and expects a pointer to it to be + * safed in info->user_ptr[1] + */ + BATADV_FLAG_NEED_HARDIF = BIT(1), };
static const struct genl_multicast_group batadv_netlink_mcgrps[] = { @@ -445,29 +453,38 @@ batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info) }
/** - * batadv_netlink_dump_hardif_entry() - Dump one hard interface into a message + * batadv_netlink_hardif_put() - Fill message with hardif attributes * @msg: Netlink message to dump into + * @bat_priv: the bat priv with all the soft interface information + * @hard_iface: hard interface which was modified + * @cmd: type of message to generate * @portid: Port making netlink request + * @seq: sequence number for message + * @flags: Additional flags for message * @cb: Control block containing additional options - * @hard_iface: Hard interface to dump * - * Return: error code, or 0 on success + * Return: 0 on success or negative error number in case of failure */ -static int -batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, - struct netlink_callback *cb, - struct batadv_hard_iface *hard_iface) +static int batadv_netlink_hardif_put(struct sk_buff *msg, + struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface, + enum batadv_nl_commands cmd, + u32 portid, u32 seq, int flags, + struct netlink_callback *cb) { struct net_device *net_dev = hard_iface->net_dev; void *hdr;
- hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, - &batadv_netlink_family, NLM_F_MULTI, - BATADV_CMD_GET_HARDIFS); + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); if (!hdr) - return -EMSGSIZE; + return -ENOBUFS; + + if (cb) + genl_dump_check_consistent(cb, hdr);
- genl_dump_check_consistent(cb, hdr); + if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, + bat_priv->soft_iface->ifindex)) + goto nla_put_failure;
if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, net_dev->ifindex) || @@ -485,24 +502,107 @@ batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, genlmsg_end(msg, hdr); return 0;
- nla_put_failure: +nla_put_failure: genlmsg_cancel(msg, hdr); return -EMSGSIZE; }
/** - * batadv_netlink_dump_hardifs() - Dump all hard interface into a messages + * batadv_netlink_notify_hardif() - send hardif attributes to listener + * @bat_priv: the bat priv with all the soft interface information + * @hard_iface: hard interface which was modified + * + * Return: 0 on success, < 0 on error + */ +static int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface) +{ + struct sk_buff *msg; + int ret; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + ret = batadv_netlink_hardif_put(msg, bat_priv, hard_iface, + BATADV_CMD_SET_HARDIF, 0, 0, 0, NULL); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + genlmsg_multicast_netns(&batadv_netlink_family, + dev_net(bat_priv->soft_iface), msg, 0, + BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); + + return 0; +} + +/** + * batadv_netlink_get_hardif() - Get hardif attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_get_hardif(struct sk_buff *skb, + struct genl_info *info) +{ + struct batadv_hard_iface *hard_iface = info->user_ptr[1]; + struct batadv_priv *bat_priv = info->user_ptr[0]; + struct sk_buff *msg; + int ret; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + ret = batadv_netlink_hardif_put(msg, bat_priv, hard_iface, + BATADV_CMD_GET_HARDIF, + info->snd_portid, info->snd_seq, 0, + NULL); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + ret = genlmsg_reply(msg, info); + + return ret; +} + +/** + * batadv_netlink_set_hardif() - Set hardif attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_set_hardif(struct sk_buff *skb, + struct genl_info *info) +{ + struct batadv_hard_iface *hard_iface = info->user_ptr[1]; + struct batadv_priv *bat_priv = info->user_ptr[0]; + + batadv_netlink_notify_hardif(bat_priv, hard_iface); + + return 0; +} + +/** + * batadv_netlink_dump_hardif() - Dump all hard interface into a messages * @msg: Netlink message to dump into * @cb: Parameters from query * * Return: error code, or length of reply message on success */ static int -batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) +batadv_netlink_dump_hardif(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; + struct batadv_priv *bat_priv; int ifindex; int portid = NETLINK_CB(cb->skb).portid; int skip = cb->args[0]; @@ -522,6 +622,8 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) return -ENODEV; }
+ bat_priv = netdev_priv(soft_iface); + rtnl_lock(); cb->seq = batadv_hardif_generation << 1 | 1;
@@ -532,8 +634,10 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) if (i++ < skip) continue;
- if (batadv_netlink_dump_hardif_entry(msg, portid, cb, - hard_iface)) { + if (batadv_netlink_hardif_put(msg, bat_priv, hard_iface, + BATADV_CMD_GET_HARDIF, + portid, cb->nlh->nlmsg_seq, + NLM_F_MULTI, cb)) { i--; break; } @@ -581,6 +685,48 @@ batadv_get_softif_from_info(struct net *net, struct genl_info *info) return ERR_PTR(-EINVAL); }
+/** + * batadv_get_hardif_from_info() - Retrieve hardif from genl attributes + * @bat_priv: the bat priv with all the soft interface information + * @net: the applicable net namespace + * @info: receiver information + * + * Return: Pointer to hard interface on success, error pointer on error + */ +static struct batadv_hard_iface * +batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net, + struct genl_info *info) +{ + struct batadv_hard_iface *hard_iface; + struct net_device *hard_dev; + unsigned int hardif_index; + + if (!info->attrs[BATADV_ATTR_HARD_IFINDEX]) + return ERR_PTR(-EINVAL); + + hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]); + + hard_dev = dev_get_by_index(net, hardif_index); + if (!hard_dev) + return ERR_PTR(-ENODEV); + + hard_iface = batadv_hardif_get_by_netdev(hard_dev); + if (!hard_iface) + goto err_put_harddev; + + if (hard_iface->soft_iface != bat_priv->soft_iface) + goto err_put_hardif; + + return hard_iface; + +err_put_hardif: + batadv_hardif_put(hard_iface); +err_put_harddev: + dev_put(hard_dev); + + return ERR_PTR(-EINVAL); +} + /** * batadv_pre_doit() - Prepare batman-adv genl doit request * @ops: requested netlink operation @@ -592,7 +738,16 @@ batadv_get_softif_from_info(struct net *net, struct genl_info *info) static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { - struct batadv_priv *bat_priv; + struct batadv_hard_iface *hard_iface; + struct batadv_priv *bat_priv = NULL; + int ret; + + if (WARN_ON(ops->internal_flags & BATADV_FLAG_NEED_HARDIF)) + return -EINVAL; + + if (WARN_ON((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) && + (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) + return -EINVAL;
if (ops->internal_flags & BATADV_FLAG_NEED_MESH) { bat_priv = batadv_get_softif_from_info(genl_info_net(info), @@ -603,7 +758,25 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, info->user_ptr[0] = bat_priv; }
+ if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF) { + hard_iface = batadv_get_hardif_from_info(bat_priv, + genl_info_net(info), + info); + if (IS_ERR(hard_iface)) { + ret = PTR_ERR(hard_iface); + goto err_put_softif; + } + + info->user_ptr[1] = hard_iface; + } + return 0; + +err_put_softif: + if (bat_priv) + dev_put(bat_priv->soft_iface); + + return ret; }
/** @@ -615,7 +788,18 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { + struct batadv_hard_iface *hard_iface; struct batadv_priv *bat_priv; + struct net_device *hard_dev; + + if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF && + info->user_ptr[1]) { + hard_iface = info->user_ptr[1]; + hard_dev = hard_iface->net_dev; + + batadv_hardif_put(hard_iface); + dev_put(hard_dev); + }
if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { bat_priv = info->user_ptr[0]; @@ -652,10 +836,13 @@ static const struct genl_ops batadv_netlink_ops[] = { .dumpit = batadv_algo_dump, }, { - .cmd = BATADV_CMD_GET_HARDIFS, - .flags = GENL_ADMIN_PERM, + .cmd = BATADV_CMD_GET_HARDIF, + /* can be retrieved by unprivileged users */ .policy = batadv_netlink_policy, - .dumpit = batadv_netlink_dump_hardifs, + .dumpit = batadv_netlink_dump_hardif, + .doit = batadv_netlink_get_hardif, + .internal_flags = BATADV_FLAG_NEED_MESH | + BATADV_FLAG_NEED_HARDIF, }, { .cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL, @@ -718,6 +905,14 @@ static const struct genl_ops batadv_netlink_ops[] = { .doit = batadv_netlink_set_mesh, .internal_flags = BATADV_FLAG_NEED_MESH, }, + { + .cmd = BATADV_CMD_SET_HARDIF, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .doit = batadv_netlink_set_hardif, + .internal_flags = BATADV_FLAG_NEED_MESH | + BATADV_FLAG_NEED_HARDIF, + }, };
struct genl_family batadv_netlink_family __ro_after_init = {
On Fri, Dec 07, 2018 at 02:58:30PM +0100, Sven Eckelmann wrote: [...]
The BATADV_CMD_GET_HARDIFS (or short version BATADV_CMD_GET_HARDIF) is reused as get command because it already allow to dump the content of other information from the slave/hard-interface which are not yet configuration specific.
"already allow" -> "already allows"
[...]
@@ -76,6 +77,13 @@ enum batadv_genl_ops_flags { * safed in info->user_ptr[0] */ BATADV_FLAG_NEED_MESH = BIT(0),
- /**
* @BATADV_FLAG_NEED_HARDIF: request requires valid hard interface in
* attribute BATADV_ATTR_HARD_IFINDEX and expects a pointer to it to be
* safed in info->user_ptr[1]
*/
- BATADV_FLAG_NEED_HARDIF = BIT(1),
safed -> saved (and same in the previous patch)
[...]
/**
- batadv_pre_doit() - Prepare batman-adv genl doit request
- @ops: requested netlink operation
@@ -592,7 +738,16 @@ batadv_get_softif_from_info(struct net *net, struct genl_info *info) static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) {
- struct batadv_priv *bat_priv;
- struct batadv_hard_iface *hard_iface;
- struct batadv_priv *bat_priv = NULL;
- int ret;
- if (WARN_ON(ops->internal_flags & BATADV_FLAG_NEED_HARDIF))
return -EINVAL;
- if (WARN_ON((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) &&
(~ops->internal_flags & BATADV_FLAG_NEED_MESH)))
return -EINVAL;
Seems like the second part is unreachable code. If BATADV_FLAG_NEED_HARDIF is set then the function returns with the first if-clause already.
On Monday, 31 December 2018 12.59.36 CET Linus Lüssing wrote: [...]
static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) {
- struct batadv_priv *bat_priv;
- struct batadv_hard_iface *hard_iface;
- struct batadv_priv *bat_priv = NULL;
- int ret;
- if (WARN_ON(ops->internal_flags & BATADV_FLAG_NEED_HARDIF))
return -EINVAL;
- if (WARN_ON((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) &&
(~ops->internal_flags & BATADV_FLAG_NEED_MESH)))
return -EINVAL;
Seems like the second part is unreachable code. If BATADV_FLAG_NEED_HARDIF is set then the function returns with the first if-clause already.
Looks like I've incorrectly splitted the patch at this position. Makes more sense when you check the next patch.
So the first check should be removed from this patch to make it less confusing.
Btw. thanks for the spelling/grammar fixes.
Kind regards, Sven
On Fri, Dec 07, 2018 at 02:58:30PM +0100, Sven Eckelmann wrote: [...]
+/**
- batadv_get_hardif_from_info() - Retrieve hardif from genl attributes
- @bat_priv: the bat priv with all the soft interface information
- @net: the applicable net namespace
- @info: receiver information
- Return: Pointer to hard interface on success, error pointer on error
- */
+static struct batadv_hard_iface * +batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net,
struct genl_info *info)
+{
- struct batadv_hard_iface *hard_iface;
- struct net_device *hard_dev;
- unsigned int hardif_index;
- if (!info->attrs[BATADV_ATTR_HARD_IFINDEX])
return ERR_PTR(-EINVAL);
- hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]);
- hard_dev = dev_get_by_index(net, hardif_index);
- if (!hard_dev)
return ERR_PTR(-ENODEV);
- hard_iface = batadv_hardif_get_by_netdev(hard_dev);
- if (!hard_iface)
goto err_put_harddev;
- if (hard_iface->soft_iface != bat_priv->soft_iface)
goto err_put_hardif;
When would this case above happen?
- return hard_iface;
It seems unnecessary to keep holding a reference to hard_dev on successful return here (and releasing it in post_doit). We return hard_iface and increase its reference count which in turn itself holds a reference to the according hard_dev already.
The usual pattern for a getter like this would be to increase the reference count for just the object returned, wouldn't it?
In any case, maybe it would make sense to mention increased refcounts in the kerneldoc? So that in case someone were reusing this function that s/he would not miss the decrease. (happens too often with these net_device reference counters...) Same for batadv_get_softif_from_info().
+err_put_hardif:
- batadv_hardif_put(hard_iface);
+err_put_harddev:
- dev_put(hard_dev);
- return ERR_PTR(-EINVAL);
+}
On Friday, 4 January 2019 01.39.54 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:30PM +0100, Sven Eckelmann wrote: [...]
+/**
- batadv_get_hardif_from_info() - Retrieve hardif from genl attributes
- @bat_priv: the bat priv with all the soft interface information
- @net: the applicable net namespace
- @info: receiver information
- Return: Pointer to hard interface on success, error pointer on error
- */
+static struct batadv_hard_iface * +batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net
*net,
struct genl_info *info)
+{
- struct batadv_hard_iface *hard_iface;
- struct net_device *hard_dev;
- unsigned int hardif_index;
- if (!info->attrs[BATADV_ATTR_HARD_IFINDEX])
return ERR_PTR(-EINVAL);
- hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]);
- hard_dev = dev_get_by_index(net, hardif_index);
- if (!hard_dev)
return ERR_PTR(-ENODEV);
- hard_iface = batadv_hardif_get_by_netdev(hard_dev);
- if (!hard_iface)
goto err_put_harddev;
- if (hard_iface->soft_iface != bat_priv->soft_iface)
goto err_put_hardif;
When would this case above happen?
When you ask for a hard interface from a different mesh interface or a hard interface without a mesh interface.
It seems unnecessary to keep holding a reference to hard_dev on successful return here (and releasing it in post_doit).
[...]
Ok.
often with these net_device reference counters...) Same for batadv_get_softif_from_info().
No, no, no, no, no, no, no and again no. The net_device is the only thing with a refcounter here. The bat_priv doesn't have a refcounter because it is just a memory region in the net_device.
Kind regards, Sven
On Fri, Jan 04, 2019 at 08:52:22AM +0100, Sven Eckelmann wrote:
It seems unnecessary to keep holding a reference to hard_dev on successful return here (and releasing it in post_doit).
[...]
Ok.
often with these net_device reference counters...) Same for batadv_get_softif_from_info().
No, no, no, no, no, no, no and again no. The net_device is the only thing with a refcounter here. The bat_priv doesn't have a refcounter because it is just a memory region in the net_device.
With "Same for batadv_get_softif_from_info()" I was talking about the
In any case, maybe it would make sense to mention increased refcounts in the kerneldoc?
That is to add a line like "Increases the refcount of foo and bar." So that users know which references to release and how to use this function just from reading the kerneldoc.
I'm not talking about bat_priv here.
On Saturday, 5 January 2019 16.12.24 CET Linus Lüssing wrote: [...]
often with these net_device reference counters...) Same for batadv_get_softif_from_info().
No, no, no, no, no, no, no and again no. The net_device is the only thing with a refcounter here. The bat_priv doesn't have a refcounter because it is just a memory region in the net_device.
With "Same for batadv_get_softif_from_info()" I was talking about the
In any case, maybe it would make sense to mention increased refcounts in the kerneldoc?
That is to add a line like "Increases the refcount of foo and bar." So that users know which references to release and how to use this function just from reading the kerneldoc.
I'm not talking about bat_priv here.
Ok
Kind regards, Sven
The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested.
Beside the mesh/soft-interface specific configuration, the VLANs on top of the mesh/soft-interface have configuration settings. The genl interface reflects this by allowing to get/set it using the vlan specific commands BATADV_CMD_GET_VLAN/BATADV_CMD_SET_VLAN.
The set command BATADV_CMD_SET_MESH will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_VLAN command message type that settings might have been changed and what the current values are.
Signed-off-by: Sven Eckelmann sven@narfation.org --- include/uapi/linux/batman_adv.h | 17 +++ net/batman-adv/netlink.c | 193 +++++++++++++++++++++++++++++++- 2 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index eb5097df..865cdf90 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -345,6 +345,11 @@ enum batadv_nl_attrs { */ BATADV_ATTR_MCAST_FLAGS_PRIV,
+ /** + * @BATADV_ATTR_VLANID: VLAN id on top of soft interface + */ + BATADV_ATTR_VLANID, + /* add attributes above here, update the policy in netlink.c */
/** @@ -465,6 +470,18 @@ enum batadv_nl_commands { */ BATADV_CMD_SET_HARDIF,
+ /** + * @BATADV_CMD_GET_VLAN: Get attributes from a VLAN of the + * current softif + */ + BATADV_CMD_GET_VLAN, + + /** + * @BATADV_CMD_SET_VLAN: Set attributes for VLAN of the + * current softif + */ + BATADV_CMD_SET_VLAN, + /* add new commands above here */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 68116eb8..30ed0672 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -30,6 +30,7 @@ #include <linux/genetlink.h> #include <linux/gfp.h> #include <linux/if_ether.h> +#include <linux/if_vlan.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/list.h> @@ -84,6 +85,13 @@ enum batadv_genl_ops_flags { * safed in info->user_ptr[1] */ BATADV_FLAG_NEED_HARDIF = BIT(1), + + /** + * @BATADV_FLAG_NEED_VLAN: request requires valid vlan in + * attribute BATADV_ATTR_VLANID and expects a pointer to it to be + * safed in info->user_ptr[1] + */ + BATADV_FLAG_NEED_VLAN = BIT(2), };
static const struct genl_multicast_group batadv_netlink_mcgrps[] = { @@ -130,6 +138,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, + [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, };
/** @@ -652,6 +661,123 @@ batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb) return msg->len; }
+/** + * batadv_netlink_vlan_put() - Fill message with vlan attributes + * @msg: Netlink message to dump into + * @bat_priv: the bat priv with all the soft interface information + * @vlan: vlan which was modified + * @cmd: type of message to generate + * @portid: Port making netlink request + * @seq: sequence number for message + * @flags: Additional flags for message + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_vlan_put(struct sk_buff *msg, + struct batadv_priv *bat_priv, + struct batadv_softif_vlan *vlan, + enum batadv_nl_commands cmd, + u32 portid, u32 seq, int flags) +{ + void *hdr; + + hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); + if (!hdr) + return -ENOBUFS; + + if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, + bat_priv->soft_iface->ifindex)) + goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_VLANID, vlan->vid & VLAN_VID_MASK)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +/** + * batadv_netlink_notify_vlan() - send vlan attributes to listener + * @bat_priv: the bat priv with all the soft interface information + * @vlan: vlan which was modified + * + * Return: 0 on success, < 0 on error + */ +static int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, + struct batadv_softif_vlan *vlan) +{ + struct sk_buff *msg; + int ret; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + ret = batadv_netlink_vlan_put(msg, bat_priv, vlan, + BATADV_CMD_SET_VLAN, 0, 0, 0); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + genlmsg_multicast_netns(&batadv_netlink_family, + dev_net(bat_priv->soft_iface), msg, 0, + BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); + + return 0; +} + +/** + * batadv_netlink_get_vlan() - Get vlan attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_get_vlan(struct sk_buff *skb, struct genl_info *info) +{ + struct batadv_softif_vlan *vlan = info->user_ptr[1]; + struct batadv_priv *bat_priv = info->user_ptr[0]; + struct sk_buff *msg; + int ret; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + ret = batadv_netlink_vlan_put(msg, bat_priv, vlan, BATADV_CMD_GET_VLAN, + info->snd_portid, info->snd_seq, 0); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + ret = genlmsg_reply(msg, info); + + return ret; +} + +/** + * batadv_netlink_set_vlan() - Get vlan attributes + * @skb: Netlink message with request data + * @info: receiver information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) +{ + struct batadv_softif_vlan *vlan = info->user_ptr[1]; + struct batadv_priv *bat_priv = info->user_ptr[0]; + + batadv_netlink_notify_vlan(bat_priv, vlan); + + return 0; +} + /** * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes * @net: the applicable net namespace @@ -727,6 +853,33 @@ batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net, return ERR_PTR(-EINVAL); }
+/** + * batadv_get_vlan_from_info() - Retrieve vlan from genl attributes + * @bat_priv: the bat priv with all the soft interface information + * @net: the applicable net namespace + * @info: receiver information + * + * Return: Pointer to vlan on success, error pointer on error + */ +static struct batadv_softif_vlan * +batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net, + struct genl_info *info) +{ + struct batadv_softif_vlan *vlan; + u16 vid; + + if (!info->attrs[BATADV_ATTR_VLANID]) + return ERR_PTR(-EINVAL); + + vid = nla_get_u16(info->attrs[BATADV_ATTR_VLANID]); + + vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); + if (!vlan) + return ERR_PTR(-ENOENT); + + return vlan; +} + /** * batadv_pre_doit() - Prepare batman-adv genl doit request * @ops: requested netlink operation @@ -740,12 +893,15 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, { struct batadv_hard_iface *hard_iface; struct batadv_priv *bat_priv = NULL; + struct batadv_softif_vlan *vlan; int ret;
- if (WARN_ON(ops->internal_flags & BATADV_FLAG_NEED_HARDIF)) + if (WARN_ON((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) && + (ops->internal_flags & BATADV_FLAG_NEED_VLAN))) return -EINVAL;
- if (WARN_ON((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) && + if (WARN_ON(((ops->internal_flags & BATADV_FLAG_NEED_HARDIF) || + (ops->internal_flags & BATADV_FLAG_NEED_VLAN)) && (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) return -EINVAL;
@@ -770,6 +926,17 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, info->user_ptr[1] = hard_iface; }
+ if (ops->internal_flags & BATADV_FLAG_NEED_VLAN) { + vlan = batadv_get_vlan_from_info(bat_priv, genl_info_net(info), + info); + if (IS_ERR(vlan)) { + ret = PTR_ERR(vlan); + goto err_put_softif; + } + + info->user_ptr[1] = vlan; + } + return 0;
err_put_softif: @@ -789,6 +956,7 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct batadv_hard_iface *hard_iface; + struct batadv_softif_vlan *vlan; struct batadv_priv *bat_priv; struct net_device *hard_dev;
@@ -801,6 +969,11 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, dev_put(hard_dev); }
+ if (ops->internal_flags & BATADV_FLAG_NEED_VLAN && info->user_ptr[1]) { + vlan = info->user_ptr[1]; + batadv_softif_vlan_put(vlan); + } + if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { bat_priv = info->user_ptr[0]; dev_put(bat_priv->soft_iface); @@ -913,6 +1086,22 @@ static const struct genl_ops batadv_netlink_ops[] = { .internal_flags = BATADV_FLAG_NEED_MESH | BATADV_FLAG_NEED_HARDIF, }, + { + .cmd = BATADV_CMD_GET_VLAN, + /* can be retrieved by unprivileged users */ + .policy = batadv_netlink_policy, + .doit = batadv_netlink_get_vlan, + .internal_flags = BATADV_FLAG_NEED_MESH | + BATADV_FLAG_NEED_VLAN, + }, + { + .cmd = BATADV_CMD_SET_VLAN, + .flags = GENL_ADMIN_PERM, + .policy = batadv_netlink_policy, + .doit = batadv_netlink_set_vlan, + .internal_flags = BATADV_FLAG_NEED_MESH | + BATADV_FLAG_NEED_VLAN, + }, };
struct genl_family batadv_netlink_family __ro_after_init = {
On Fri, Dec 07, 2018 at 02:58:31PM +0100, Sven Eckelmann wrote:
The batman-adv configuration interface was implemented solely using sysfs. This approach was condemned by non-batadv developers as "huge mistake". Instead a netlink/genl based implementation was suggested.
Beside the mesh/soft-interface specific configuration, the VLANs on top of the mesh/soft-interface have configuration settings. The genl interface reflects this by allowing to get/set it using the vlan specific commands BATADV_CMD_GET_VLAN/BATADV_CMD_SET_VLAN.
The set command BATADV_CMD_SET_MESH will also notify interested userspace listeners of the "config" mcast group using the BATADV_CMD_SET_VLAN command message type that settings might have been changed and what the current values are.
Signed-off-by: Sven Eckelmann sven@narfation.org
Looks good.
Initially I was a bit confused with batadv_pre_doit() and thought you were missing to free the hard_iface in the "if (IS_ERR(vlan))" case. But then I remembered your initial WARN_ON() which ensures that hardif and vlan are exclusive.
The mesh interface can delay OGM messages to aggregate different ogms together in a single OGM packet.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_AGGREGATED_OGMS attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 12 ++++++++++++ 2 files changed, 18 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 865cdf90..a01d90ed 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -350,6 +350,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_VLANID,
+ /** + * @BATADV_ATTR_AGGREGATED_OGMS: whether the batman protocol messages + * of the mesh mesh interface shall be aggregated or not. + */ + BATADV_ATTR_AGGREGATED_OGMS, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 30ed0672..862d47c4 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -139,6 +139,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, + [BATADV_ATTR_AGGREGATED_OGMS] = { .type = NLA_U8 }, };
/** @@ -214,6 +215,10 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; }
+ if (nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS, + !!atomic_read(&bat_priv->aggregated_ogms))) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -295,6 +300,13 @@ static int batadv_netlink_get_mesh(struct sk_buff *skb, struct genl_info *info) static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) { struct batadv_priv *bat_priv = info->user_ptr[0]; + struct nlattr *attr; + + if (info->attrs[BATADV_ATTR_AGGREGATED_OGMS]) { + attr = info->attrs[BATADV_ATTR_AGGREGATED_OGMS]; + + atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr)); + }
batadv_netlink_notify_mesh(bat_priv);
On Fri, Dec 07, 2018 at 02:58:32PM +0100, Sven Eckelmann wrote:
- /**
* @BATADV_ATTR_AGGREGATED_OGMS: whether the batman protocol messages
* of the mesh mesh interface shall be aggregated or not.
*/
- BATADV_ATTR_AGGREGATED_OGMS,
I'm wondering, would it make sense to take this opportunity to rename this to BATADV_ATTR_AGGREGATION? In case we were adding aggregation support to something other than OGMs in the future.
(and maybe even make it a u32 to be able to potentially use it as a bitfield with a useable length?)
And I know, the generic aggregation patchset was rejected. But on the other hand I don't think that OGMs are that special that they will always be the only packet type worth aggregating.
On Friday, 4 January 2019 02.40.06 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:32PM +0100, Sven Eckelmann wrote:
- /**
* @BATADV_ATTR_AGGREGATED_OGMS: whether the batman protocol messages
* of the mesh mesh interface shall be aggregated or not.
*/
- BATADV_ATTR_AGGREGATED_OGMS,
I'm wondering, would it make sense to take this opportunity to rename this to BATADV_ATTR_AGGREGATION? In case we were adding aggregation support to something other than OGMs in the future.
(and maybe even make it a u32 to be able to potentially use it as a bitfield with a useable length?)
And I know, the generic aggregation patchset was rejected. But on the other hand I don't think that OGMs are that special that they will always be the only packet type worth aggregating.
Any suggestions from Jiri regarding this?
Kind regards, Sven
On Fri, Dec 07, 2018 at 02:58:32PM +0100, Sven Eckelmann wrote:
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 865cdf90..a01d90ed 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -350,6 +350,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_VLANID,
- /**
* @BATADV_ATTR_AGGREGATED_OGMS: whether the batman protocol messages
* of the mesh mesh interface shall be aggregated or not.
*/
- BATADV_ATTR_AGGREGATED_OGMS,
"mesh mesh" -> "mesh"
The mesh interface can drop messages between clients to implement a mesh-wide AP isolation.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH and BATADV_CMD_SET_VLAN/BATADV_CMD_GET_VLAN commands allow to set/get the configuration of this feature using the BATADV_ATTR_AP_ISOLATION attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
This feature also requires that skbuff which should be handled as isolated are marked. The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the mark/mask using the u32 attributes BATADV_ATTR_ISOLATION_MARK and BATADV_ATTR_ISOLATION_MASK.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Antonio Quartulli a@unstable.cc --- include/uapi/linux/batman_adv.h | 18 +++++++ net/batman-adv/netlink.c | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index a01d90ed..75738032 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -356,6 +356,24 @@ enum batadv_nl_attrs { */ BATADV_ATTR_AGGREGATED_OGMS,
+ /** + * @BATADV_ATTR_AP_ISOLATION: whether the data traffic going from a + * wireless client to another wireless client will be silently dropped. + */ + BATADV_ATTR_AP_ISOLATION, + + /** + * @BATADV_ATTR_ISOLATION_MARK: the isolation mark which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MARK, + + /** + * @BATADV_ATTR_ISOLATION_MASK: the isolation (bit)mask which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MASK, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 862d47c4..217c4b30 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -140,6 +140,9 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, [BATADV_ATTR_AGGREGATED_OGMS] = { .type = NLA_U8 }, + [BATADV_ATTR_AP_ISOLATION] = { .type = NLA_U8 }, + [BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 }, + [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, };
/** @@ -157,6 +160,51 @@ batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) return attr ? nla_get_u32(attr) : 0; }
+/** + * batadv_netlink_mesh_put_ap_isolation() - Add ap_isolation softif attribute + * @msg: Netlink message to dump into + * @bat_priv: the bat priv with all the soft interface information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_mesh_put_ap_isolation(struct sk_buff *msg, + struct batadv_priv *bat_priv) +{ + struct batadv_softif_vlan *vlan; + u8 ap_isolation; + + vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); + if (!vlan) + return 0; + + ap_isolation = atomic_read(&vlan->ap_isolation); + batadv_softif_vlan_put(vlan); + + return nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION, !!ap_isolation); +} + +/** + * batadv_option_set_ap_isolation() - Set ap_isolation from genl msg + * @attr: parsed BATADV_ATTR_AP_ISOLATION attribute + * @bat_priv: the bat priv with all the soft interface information + * + * Return: 0 on success or negative error number in case of failure + */ +static int batadv_netlink_set_mesh_ap_isolation(struct nlattr *attr, + struct batadv_priv *bat_priv) +{ + struct batadv_softif_vlan *vlan; + + vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); + if (!vlan) + return -ENOENT; + + atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + batadv_softif_vlan_put(vlan); + + return 0; +} + /** * batadv_netlink_mesh_put() - Fill message with mesh attributes * @msg: Netlink message to dump into @@ -219,6 +267,17 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, !!atomic_read(&bat_priv->aggregated_ogms))) goto nla_put_failure;
+ if (batadv_netlink_mesh_put_ap_isolation(msg, bat_priv)) + goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MARK, + bat_priv->isolation_mark)) + goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MASK, + bat_priv->isolation_mark_mask)) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -308,6 +367,24 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr)); }
+ if (info->attrs[BATADV_ATTR_AP_ISOLATION]) { + attr = info->attrs[BATADV_ATTR_AP_ISOLATION]; + + batadv_netlink_set_mesh_ap_isolation(attr, bat_priv); + } + + if (info->attrs[BATADV_ATTR_ISOLATION_MARK]) { + attr = info->attrs[BATADV_ATTR_ISOLATION_MARK]; + + bat_priv->isolation_mark = nla_get_u32(attr); + } + + if (info->attrs[BATADV_ATTR_ISOLATION_MASK]) { + attr = info->attrs[BATADV_ATTR_ISOLATION_MASK]; + + bat_priv->isolation_mark_mask = nla_get_u32(attr); + } + batadv_netlink_notify_mesh(bat_priv);
return 0; @@ -704,6 +781,10 @@ static int batadv_netlink_vlan_put(struct sk_buff *msg, if (nla_put_u32(msg, BATADV_ATTR_VLANID, vlan->vid & VLAN_VID_MASK)) goto nla_put_failure;
+ if (nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION, + !!atomic_read(&vlan->ap_isolation))) + goto nla_put_failure; + genlmsg_end(msg, hdr); return 0;
@@ -784,6 +865,13 @@ static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) { struct batadv_softif_vlan *vlan = info->user_ptr[1]; struct batadv_priv *bat_priv = info->user_ptr[0]; + struct nlattr *attr; + + if (info->attrs[BATADV_ATTR_AP_ISOLATION]) { + attr = info->attrs[BATADV_ATTR_AP_ISOLATION]; + + atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + }
batadv_netlink_notify_vlan(bat_priv, vlan);
The mesh interface can use multiple slave/hard-interface ports at the same time to transport the traffic to other nodes.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_BONDING attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Simon Wunderlich sw@simonwunderlich.de --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 11 +++++++++++ 2 files changed, 17 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 75738032..d209c468 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -374,6 +374,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_ISOLATION_MASK,
+ /** + * @BATADV_ATTR_BONDING: whether the data traffic going through the + * mesh will be sent using multiple interfaces at the same time. + */ + BATADV_ATTR_BONDING, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 217c4b30..a836a8f1 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -143,6 +143,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_AP_ISOLATION] = { .type = NLA_U8 }, [BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 }, [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, + [BATADV_ATTR_BONDING] = { .type = NLA_U8 }, };
/** @@ -278,6 +279,10 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, bat_priv->isolation_mark_mask)) goto nla_put_failure;
+ if (nla_put_u8(msg, BATADV_ATTR_BONDING, + !!atomic_read(&bat_priv->bonding))) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -385,6 +390,12 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) bat_priv->isolation_mark_mask = nla_get_u32(attr); }
+ if (info->attrs[BATADV_ATTR_BONDING]) { + attr = info->attrs[BATADV_ATTR_BONDING]; + + atomic_set(&bat_priv->bonding, !!nla_get_u8(attr)); + } + batadv_netlink_notify_mesh(bat_priv);
return 0;
The mesh interface can try to detect loops in the same mesh caused by (indirectly) bridged mesh/soft-interfaces of different nodes. Some of the loops can also be resolved without breaking the mesh.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Simon Wunderlich sw@simonwunderlich.de --- include/uapi/linux/batman_adv.h | 7 +++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index d209c468..711379ef 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -380,6 +380,13 @@ enum batadv_nl_attrs { */ BATADV_ATTR_BONDING,
+ /** + * @BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE: whether the bridge loop avoidance + * feature is enabled. This feature detects and avoids loops between + * the mesh and devices bridged with the soft interface + */ + BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index a836a8f1..95181808 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -144,6 +144,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 }, [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, [BATADV_ATTR_BONDING] = { .type = NLA_U8 }, + [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE] = { .type = NLA_U8 }, };
/** @@ -283,6 +284,12 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, !!atomic_read(&bat_priv->bonding))) goto nla_put_failure;
+#ifdef CONFIG_BATMAN_ADV_BLA + if (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE, + !!atomic_read(&bat_priv->bridge_loop_avoidance))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_BLA */ + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -396,6 +403,16 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) atomic_set(&bat_priv->bonding, !!nla_get_u8(attr)); }
+#ifdef CONFIG_BATMAN_ADV_BLA + if (info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE]) { + attr = info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE]; + + atomic_set(&bat_priv->bridge_loop_avoidance, + !!nla_get_u8(attr)); + batadv_bla_status_update(bat_priv->soft_iface); + } +#endif /* CONFIG_BATMAN_ADV_BLA */ + batadv_netlink_notify_mesh(bat_priv);
return 0;
The mesh interface can use a distributed hash table to answer ARP requests without flooding the request through the whole mesh.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_DISTRIBUTED_ARP_TABLE attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Antonio Quartulli a@unstable.cc --- include/uapi/linux/batman_adv.h | 8 ++++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 711379ef..618c727c 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -387,6 +387,14 @@ enum batadv_nl_attrs { */ BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE,
+ /** + * @BATADV_ATTR_DISTRIBUTED_ARP_TABLE: whether the distributed arp table + * feature is enabled. This feature uses a distributed hash table to + * answer ARP requests without flooding the request through the whole + * mesh. + */ + BATADV_ATTR_DISTRIBUTED_ARP_TABLE, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 95181808..d93039b2 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -145,6 +145,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, [BATADV_ATTR_BONDING] = { .type = NLA_U8 }, [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE] = { .type = NLA_U8 }, + [BATADV_ATTR_DISTRIBUTED_ARP_TABLE] = { .type = NLA_U8 }, };
/** @@ -290,6 +291,12 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BLA */
+#ifdef CONFIG_BATMAN_ADV_DAT + if (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE, + !!atomic_read(&bat_priv->distributed_arp_table))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_DAT */ + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -413,6 +420,16 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } #endif /* CONFIG_BATMAN_ADV_BLA */
+#ifdef CONFIG_BATMAN_ADV_DAT + if (info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE]) { + attr = info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE]; + + atomic_set(&bat_priv->distributed_arp_table, + !!nla_get_u8(attr)); + batadv_dat_status_update(bat_priv->soft_iface); + } +#endif /* CONFIG_BATMAN_ADV_DAT */ + batadv_netlink_notify_mesh(bat_priv);
return 0;
The mesh interface can fragment unicast packets when the packet size exceeds the outgoing slave/hard-interface MTU.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_FRAGMENTATION attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Andreas Langer an.langer@gmx.de Cc: Martin Hundeboll martin@hundeboll.net Cc: Marek Lindner mareklindner@neomailbox.ch --- include/uapi/linux/batman_adv.h | 7 +++++++ net/batman-adv/netlink.c | 12 ++++++++++++ 2 files changed, 19 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 618c727c..5c58d3b6 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -395,6 +395,13 @@ enum batadv_nl_attrs { */ BATADV_ATTR_DISTRIBUTED_ARP_TABLE,
+ /** + * @BATADV_ATTR_FRAGMENTATION: whether the data traffic going through + * the mesh will be fragmented or silently discarded if the packet size + * exceeds the outgoing interface MTU. + */ + BATADV_ATTR_FRAGMENTATION, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index d93039b2..d7d5f196 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -146,6 +146,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_BONDING] = { .type = NLA_U8 }, [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE] = { .type = NLA_U8 }, [BATADV_ATTR_DISTRIBUTED_ARP_TABLE] = { .type = NLA_U8 }, + [BATADV_ATTR_FRAGMENTATION] = { .type = NLA_U8 }, };
/** @@ -297,6 +298,10 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DAT */
+ if (nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION, + !!atomic_read(&bat_priv->fragmentation))) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -430,6 +435,13 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } #endif /* CONFIG_BATMAN_ADV_DAT */
+ if (info->attrs[BATADV_ATTR_FRAGMENTATION]) { + attr = info->attrs[BATADV_ATTR_FRAGMENTATION]; + + atomic_set(&bat_priv->fragmentation, !!nla_get_u8(attr)); + batadv_update_min_mtu(bat_priv->soft_iface); + } + batadv_netlink_notify_mesh(bat_priv);
return 0;
The mesh/soft-interface can optimize the handling of DHCP packets. Instead of flooding them through the whole mesh, it can be forwarded as unicast to a specific gateway server. The originator which injects the packets in the mesh has to select (based on sel_class thresholds) a responsible gateway server. This is done by switching this originator to the gw_mode client. The servers announce their forwarding bandwidth (download/upload) when the gw_mode server was selected.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the attributes:
* u8 BATADV_ATTR_GW_MODE (0 == off, 1 == client, 2 == server) * u32 BATADV_ATTR_GW_BANDWIDTH_DOWN (in 100 kbit/s steps) * u32 BATADV_ATTR_GW_BANDWIDTH_UP (in 100 kbit/s steps) * u32 BATADV_ATTR_GW_SEL_CLASS
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch Cc: Antonio Quartulli a@unstable.cc --- include/uapi/linux/batman_adv.h | 40 ++++++++++++++ net/batman-adv/gateway_client.c | 1 - net/batman-adv/gateway_common.c | 1 + net/batman-adv/gateway_common.h | 6 --- net/batman-adv/netlink.c | 92 +++++++++++++++++++++++++++++++++ net/batman-adv/soft-interface.c | 2 +- net/batman-adv/sysfs.c | 1 + 7 files changed, 135 insertions(+), 8 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 5c58d3b6..0d45e807 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -139,6 +139,20 @@ enum batadv_mcast_flags_priv { BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING = (1 << 4), };
+/** + * enum batadv_gw_modes - gateway mode of node + */ +enum batadv_gw_modes { + /** @BATADV_GW_MODE_OFF: gw mode disabled */ + BATADV_GW_MODE_OFF, + + /** @BATADV_GW_MODE_CLIENT: send DHCP requests to gw servers */ + BATADV_GW_MODE_CLIENT, + + /** @BATADV_GW_MODE_SERVER: announce itself as gatway server */ + BATADV_GW_MODE_SERVER, +}; + /** * enum batadv_nl_attrs - batman-adv netlink attributes */ @@ -402,6 +416,32 @@ enum batadv_nl_attrs { */ BATADV_ATTR_FRAGMENTATION,
+ /** + * @BATADV_ATTR_GW_BANDWIDTH_DOWN: defines the download bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_DOWN, + + /** + * @BATADV_ATTR_GW_BANDWIDTH_UP: defines the upload bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_UP, + + /** + * @BATADV_ATTR_GW_MODE: defines the state of the gateway features. + * Possible values are specified in enum batadv_gw_modes + */ + BATADV_ATTR_GW_MODE, + + /** + * @BATADV_ATTR_GW_SEL_CLASS: defines the selection criteria this node + * will use to choose a gateway if gw_mode was set to 'client'. + */ + BATADV_ATTR_GW_SEL_CLASS, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 9d8e5eda..2373903c 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -47,7 +47,6 @@ #include <uapi/linux/batadv_packet.h> #include <uapi/linux/batman_adv.h>
-#include "gateway_common.h" #include "hard-interface.h" #include "log.h" #include "netlink.h" diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 936c107f..08b62271 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -28,6 +28,7 @@ #include <linux/stddef.h> #include <linux/string.h> #include <uapi/linux/batadv_packet.h> +#include <uapi/linux/batman_adv.h>
#include "gateway_client.h" #include "log.h" diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h index 80afb279..cd1c5f54 100644 --- a/net/batman-adv/gateway_common.h +++ b/net/batman-adv/gateway_common.h @@ -25,12 +25,6 @@
struct net_device;
-enum batadv_gw_modes { - BATADV_GW_MODE_OFF, - BATADV_GW_MODE_CLIENT, - BATADV_GW_MODE_SERVER, -}; - /** * enum batadv_bandwidth_units - bandwidth unit types */ diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index d7d5f196..e79a61a6 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -51,6 +51,7 @@ #include "bridge_loop_avoidance.h" #include "distributed-arp-table.h" #include "gateway_client.h" +#include "gateway_common.h" #include "hard-interface.h" #include "multicast.h" #include "originator.h" @@ -147,6 +148,10 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE] = { .type = NLA_U8 }, [BATADV_ATTR_DISTRIBUTED_ARP_TABLE] = { .type = NLA_U8 }, [BATADV_ATTR_FRAGMENTATION] = { .type = NLA_U8 }, + [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NLA_U32 }, + [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NLA_U32 }, + [BATADV_ATTR_GW_MODE] = { .type = NLA_U8 }, + [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, };
/** @@ -302,6 +307,28 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, !!atomic_read(&bat_priv->fragmentation))) goto nla_put_failure;
+ if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, + atomic_read(&bat_priv->gw.bandwidth_down))) + goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, + atomic_read(&bat_priv->gw.bandwidth_up))) + goto nla_put_failure; + + if (nla_put_u8(msg, BATADV_ATTR_GW_MODE, + atomic_read(&bat_priv->gw.mode))) + goto nla_put_failure; + + if (bat_priv->algo_ops->gw.get_best_gw_node && + bat_priv->algo_ops->gw.is_eligible) { + /* GW selection class is not available if the routing algorithm + * in use does not implement the GW API + */ + if (nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, + atomic_read(&bat_priv->gw.sel_class))) + goto nla_put_failure; + } + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -442,6 +469,71 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) batadv_update_min_mtu(bat_priv->soft_iface); }
+ if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { + attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]; + + atomic_set(&bat_priv->gw.bandwidth_down, nla_get_u32(attr)); + batadv_gw_tvlv_container_update(bat_priv); + } + + if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { + attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]; + + atomic_set(&bat_priv->gw.bandwidth_up, nla_get_u32(attr)); + batadv_gw_tvlv_container_update(bat_priv); + } + + if (info->attrs[BATADV_ATTR_GW_MODE]) { + u8 gw_mode; + + attr = info->attrs[BATADV_ATTR_GW_MODE]; + gw_mode = nla_get_u8(attr); + + if (gw_mode <= BATADV_GW_MODE_SERVER) { + /* Invoking batadv_gw_reselect() is not enough to really + * de-select the current GW. It will only instruct the + * gateway client code to perform a re-election the next + * time that this is needed. + * + * When gw client mode is being switched off the current + * GW must be de-selected explicitly otherwise no GW_ADD + * uevent is thrown on client mode re-activation. This + * is operation is performed in + * batadv_gw_check_client_stop(). + */ + batadv_gw_reselect(bat_priv); + + /* always call batadv_gw_check_client_stop() before + * changing the gateway state + */ + batadv_gw_check_client_stop(bat_priv); + atomic_set(&bat_priv->gw.mode, gw_mode); + batadv_gw_tvlv_container_update(bat_priv); + } + } + + if (info->attrs[BATADV_ATTR_GW_SEL_CLASS] && + bat_priv->algo_ops->gw.get_best_gw_node && + bat_priv->algo_ops->gw.is_eligible) { + /* setting the GW selection class is allowed only if the routing + * algorithm in use implements the GW API + */ + + u32 sel_class_max = 0xffffffffu; + u32 sel_class; + + attr = info->attrs[BATADV_ATTR_GW_SEL_CLASS]; + sel_class = nla_get_u32(attr); + + if (!bat_priv->algo_ops->gw.store_sel_class) + sel_class_max = BATADV_TQ_MAX_VALUE; + + if (sel_class >= 1 && sel_class <= sel_class_max) { + atomic_set(&bat_priv->gw.sel_class, sel_class); + batadv_gw_reselect(bat_priv); + } + } + batadv_netlink_notify_mesh(bat_priv);
return 0; diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 5db5a0a4..d158ac70 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -50,13 +50,13 @@ #include <linux/string.h> #include <linux/types.h> #include <uapi/linux/batadv_packet.h> +#include <uapi/linux/batman_adv.h>
#include "bat_algo.h" #include "bridge_loop_avoidance.h" #include "debugfs.h" #include "distributed-arp-table.h" #include "gateway_client.h" -#include "gateway_common.h" #include "hard-interface.h" #include "multicast.h" #include "network-coding.h" diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 09427fc6..344e5787 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -40,6 +40,7 @@ #include <linux/stringify.h> #include <linux/workqueue.h> #include <uapi/linux/batadv_packet.h> +#include <uapi/linux/batman_adv.h>
#include "bridge_loop_avoidance.h" #include "distributed-arp-table.h"
The TQ (B.A.T.M.A.N. IV) and throughput values (B.A.T.M.A.N. V) are reduced when they are forwarded. One of the reductions is the penalty for traversing an additional hop. This hop_penalty (0-255) defines the percentage of reduction (0-100%).
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the u8 BATADV_ATTR_HOP_PENALTY attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Linus Lüssing linus.luessing@c0d3.blue Cc: Marek Lindner mareklindner@neomailbox.ch Cc: Antonio Quartulli a@unstable.cc Cc: Simon Wunderlich sw@simonwunderlich.de --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 11 +++++++++++ 2 files changed, 17 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 0d45e807..7cc69802 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -442,6 +442,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_GW_SEL_CLASS,
+ /** + * @BATADV_ATTR_HOP_PENALTY: defines the penalty which will be applied + * to an originator message's tq-field on every hop. + */ + BATADV_ATTR_HOP_PENALTY, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index e79a61a6..bbea6ac0 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -152,6 +152,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NLA_U32 }, [BATADV_ATTR_GW_MODE] = { .type = NLA_U8 }, [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, + [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, };
/** @@ -329,6 +330,10 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; }
+ if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, + atomic_read(&bat_priv->hop_penalty))) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -534,6 +539,12 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } }
+ if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { + attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; + + atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr)); + } + batadv_netlink_notify_mesh(bat_priv);
return 0;
In contrast to other modules, batman-adv allows to set the debug message verbosity per mesh/soft-interface and not per module (via modparam).
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the u32 (bitmask) BATADV_ATTR_LOG_LEVEL attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 7cc69802..efc06449 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -448,6 +448,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_HOP_PENALTY,
+ /** + * @BATADV_ATTR_LOG_LEVEL: bitmask with to define which debug messages + * should be send to the debug log/trace ring buffer + */ + BATADV_ATTR_LOG_LEVEL, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index bbea6ac0..8e3a1b6e 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -53,6 +53,7 @@ #include "gateway_client.h" #include "gateway_common.h" #include "hard-interface.h" +#include "log.h" #include "multicast.h" #include "originator.h" #include "soft-interface.h" @@ -153,6 +154,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_MODE] = { .type = NLA_U8 }, [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, + [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, };
/** @@ -334,6 +336,12 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, atomic_read(&bat_priv->hop_penalty))) goto nla_put_failure;
+#ifdef CONFIG_BATMAN_ADV_DEBUG + if (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, + atomic_read(&bat_priv->log_level))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_DEBUG */ + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -545,6 +553,15 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr)); }
+#ifdef CONFIG_BATMAN_ADV_DEBUG + if (info->attrs[BATADV_ATTR_LOG_LEVEL]) { + attr = info->attrs[BATADV_ATTR_LOG_LEVEL]; + + atomic_set(&bat_priv->log_level, + nla_get_u32(attr) & BATADV_DBG_ALL); + } +#endif /* CONFIG_BATMAN_ADV_DEBUG */ + batadv_netlink_notify_mesh(bat_priv);
return 0;
The mesh interface can optimize the flooding of multicast packets based on the content of the global translation tables.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_MULTICAST_MODE attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Linus Lüssing linus.luessing@c0d3.blue --- include/uapi/linux/batman_adv.h | 8 ++++++++ net/batman-adv/netlink.c | 15 +++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index efc06449..514acc06 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -454,6 +454,14 @@ enum batadv_nl_attrs { */ BATADV_ATTR_LOG_LEVEL,
+ /** + * @BATADV_ATTR_MULTICAST_MODE: whether multicast optimizations are + * enabled or disabled. If set to zero then all nodes in the mesh are + * going to use classic flooding for any multicast packet with no + * optimizations. + */ + BATADV_ATTR_MULTICAST_MODE, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 8e3a1b6e..32762003 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -155,6 +155,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, + [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 }, };
/** @@ -342,6 +343,12 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DEBUG */
+#ifdef CONFIG_BATMAN_ADV_MCAST + if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_MODE, + !!atomic_read(&bat_priv->multicast_mode))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_MCAST */ + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -562,6 +569,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } #endif /* CONFIG_BATMAN_ADV_DEBUG */
+#ifdef CONFIG_BATMAN_ADV_MCAST + if (info->attrs[BATADV_ATTR_MULTICAST_MODE]) { + attr = info->attrs[BATADV_ATTR_MULTICAST_MODE]; + + atomic_set(&bat_priv->multicast_mode, !!nla_get_u8(attr)); + } +#endif /* CONFIG_BATMAN_ADV_MCAST */ + batadv_netlink_notify_mesh(bat_priv);
return 0;
On Fri, Dec 07, 2018 at 02:58:41PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 8e3a1b6e..32762003 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -155,6 +155,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 },
- [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 },
};
Since the name is more generic than just a flag, would it make sense to make this a U32, just to stay flexible for the future?
(I don't have any specific ideas or plans to use more values for it right now, though)
On Friday, 4 January 2019 02.57.26 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:41PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 8e3a1b6e..32762003 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -155,6 +155,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 },
- [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 },
};
Since the name is more generic than just a flag, would it make sense to make this a U32, just to stay flexible for the future?
(I don't have any specific ideas or plans to use more values for it right now, though)
Please discuss this with Jiro because he told us to use u8.
Kind regards, Sven
Fri, Jan 04, 2019 at 08:44:38AM CET, sven@narfation.org wrote:
On Friday, 4 January 2019 02.57.26 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:41PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 8e3a1b6e..32762003 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -155,6 +155,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 },
- [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 },
};
Since the name is more generic than just a flag, would it make sense to make this a U32, just to stay flexible for the future?
If the attribute is supposed to be just a bool, the name would be probably better to change to "BATADV_ATTR_MULTICAST_ENABLED" or something.
(I don't have any specific ideas or plans to use more values for it right now, though)
Please discuss this with Jiro because he told us to use u8.
Kind regards, Sven
On Fri, Jan 04, 2019 at 08:51:56AM +0000, Jiri Pirko wrote:
Fri, Jan 04, 2019 at 08:44:38AM CET, sven@narfation.org wrote:
On Friday, 4 January 2019 02.57.26 CET Linus Lüssing wrote:
On Fri, Dec 07, 2018 at 02:58:41PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 8e3a1b6e..32762003 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -155,6 +155,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 },
- [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 },
};
Since the name is more generic than just a flag, would it make sense to make this a U32, just to stay flexible for the future?
If the attribute is supposed to be just a bool, the name would be probably better to change to "BATADV_ATTR_MULTICAST_ENABLED" or something.
Hm, BATADV_ATTR_MULTICAST_ENABLED sounds confusing to me. In a layer 2 mesh network, multicast always needs to be enabled for things like IP to work.
So setting this to 0 does not disable multicast.
What this option does is using "classic flooding" (0) for multicast packets or dropping/unicasting if possible, if IGMP/MLD snooping detected such potential (1).
And since there were many discussions regarding which additional techniques and algorithms could be implemented I would expect more options to follow.
And for complementary techniques, a bitfield of 32 bits size could be useful, I guess?
The mesh interface can use (in an homogeneous mesh) network coding, a mechanism that aims to increase the overall network throughput by fusing multiple packets in one transmission.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the BATADV_ATTR_NETWORK_CODING attribute. Setting the u8 to zero will disable this feature and setting it to something else is enabling this feature.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Martin Hundeboll martin@hundeboll.net Cc: Marek Lindner mareklindner@neomailbox.ch --- include/uapi/linux/batman_adv.h | 7 +++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 514acc06..7e8a086f 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -462,6 +462,13 @@ enum batadv_nl_attrs { */ BATADV_ATTR_MULTICAST_MODE,
+ /** + * @BATADV_ATTR_NETWORK_CODING: whether Network Coding (using some magic + * to send fewer wifi packets but still the same content) is enabled or + * not. + */ + BATADV_ATTR_NETWORK_CODING, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 32762003..bdfea982 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -55,6 +55,7 @@ #include "hard-interface.h" #include "log.h" #include "multicast.h" +#include "network-coding.h" #include "originator.h" #include "soft-interface.h" #include "tp_meter.h" @@ -156,6 +157,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 }, + [BATADV_ATTR_NETWORK_CODING] = { .type = NLA_U8 }, };
/** @@ -349,6 +351,12 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_MCAST */
+#ifdef CONFIG_BATMAN_ADV_NC + if (nla_put_u8(msg, BATADV_ATTR_NETWORK_CODING, + !!atomic_read(&bat_priv->network_coding))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_NC */ + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -577,6 +585,15 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } #endif /* CONFIG_BATMAN_ADV_MCAST */
+#ifdef CONFIG_BATMAN_ADV_NC + if (info->attrs[BATADV_ATTR_NETWORK_CODING]) { + attr = info->attrs[BATADV_ATTR_NETWORK_CODING]; + + atomic_set(&bat_priv->network_coding, !!nla_get_u8(attr)); + batadv_nc_status_update(bat_priv->soft_iface); + } +#endif /* CONFIG_BATMAN_ADV_NC */ + batadv_netlink_notify_mesh(bat_priv);
return 0;
The OGM packets are transmitted every orig_interval milliseconds. This value can be changed using the configuration interface.
The BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH commands allow to set/get the configuration of this feature using the u32 BATADV_ATTR_ORIG_INTERVAL attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 7e8a086f..b8cb26d2 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -469,6 +469,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_NETWORK_CODING,
+ /** + * @BATADV_ATTR_ORIG_INTERVAL: defines the interval in milliseconds in + * which batman sends its protocol messages. + */ + BATADV_ATTR_ORIG_INTERVAL, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index bdfea982..831678fd 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -158,6 +158,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 }, [BATADV_ATTR_NETWORK_CODING] = { .type = NLA_U8 }, + [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, };
/** @@ -357,6 +358,10 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_NC */
+ if (nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, + atomic_read(&bat_priv->orig_interval))) + goto nla_put_failure; + batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr); @@ -594,6 +599,18 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) } #endif /* CONFIG_BATMAN_ADV_NC */
+ if (info->attrs[BATADV_ATTR_ORIG_INTERVAL]) { + u32 orig_interval; + + attr = info->attrs[BATADV_ATTR_ORIG_INTERVAL]; + orig_interval = nla_get_u32(attr); + + orig_interval = min_t(u32, orig_interval, INT_MAX); + orig_interval = max_t(u32, orig_interval, 2 * BATADV_JITTER); + + atomic_set(&bat_priv->orig_interval, orig_interval); + } + batadv_netlink_notify_mesh(bat_priv);
return 0;
The ELP packets are transmitted every elp_interval milliseconds on an slave/hard-interface. This value can be changed using the configuration interface.
The BATADV_CMD_SET_HARDIF/BATADV_CMD_GET_HARDIF commands allow to set/get the configuration of this feature using the u32 BATADV_ATTR_ELP_INTERVAL attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Linus Lüssing linus.luessing@c0d3.blue --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/netlink.c | 17 +++++++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index b8cb26d2..716471df 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -475,6 +475,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_ORIG_INTERVAL,
+ /** + * @BATADV_ATTR_ELP_INTERVAL: defines the interval in milliseconds in + * which batman emits probing packets for neighbor sensing (ELP). + */ + BATADV_ATTR_ELP_INTERVAL, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 831678fd..5144c350 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -159,6 +159,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_MULTICAST_MODE] = { .type = NLA_U8 }, [BATADV_ATTR_NETWORK_CODING] = { .type = NLA_U8 }, [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 }, };
/** @@ -823,6 +824,12 @@ static int batadv_netlink_hardif_put(struct sk_buff *msg, goto nla_put_failure; }
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V + if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL, + atomic_read(&hard_iface->bat_v.elp_interval))) + goto nla_put_failure; +#endif /* CONFIG_BATMAN_ADV_BATMAN_V */ + genlmsg_end(msg, hdr); return 0;
@@ -908,6 +915,16 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, struct batadv_hard_iface *hard_iface = info->user_ptr[1]; struct batadv_priv *bat_priv = info->user_ptr[0];
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V + struct nlattr *attr; + + if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) { + attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; + + atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr)); + } +#endif /* CONFIG_BATMAN_ADV_BATMAN_V */ + batadv_netlink_notify_hardif(bat_priv, hard_iface);
return 0;
The B.A.T.M.A.N. V implementation tries to estimate the link throughput of an interface to an originator using different automatic methods. It is still possible to overwrite it the link throughput for all reachable originators via this interface.
The BATADV_CMD_SET_HARDIF/BATADV_CMD_GET_HARDIF commands allow to set/get the configuration of this feature using the u32 BATADV_ATTR_THROUGHPUT_OVERRIDE attribute. The used unit is in 100 Kbit/s. If the value is set to 0 then batman-adv will try to estimate the throughput by itself.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Antonio Quartulli a@unstable.cc --- include/uapi/linux/batman_adv.h | 8 ++++++++ net/batman-adv/netlink.c | 12 ++++++++++++ 2 files changed, 20 insertions(+)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 716471df..b5a245ef 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -481,6 +481,14 @@ enum batadv_nl_attrs { */ BATADV_ATTR_ELP_INTERVAL,
+ /** + * @BATADV_ATTR_THROUGHPUT_OVERRIDE: defines the throughput value to be + * used by B.A.T.M.A.N. V when estimating the link throughput using + * this interface. If the value is set to 0 then batman-adv will try to + * estimate the throughput by itself. + */ + BATADV_ATTR_THROUGHPUT_OVERRIDE, + /* add attributes above here, update the policy in netlink.c */
/** diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 5144c350..4065d871 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -160,6 +160,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_NETWORK_CODING] = { .type = NLA_U8 }, [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, [BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NLA_U32 }, };
/** @@ -828,6 +829,10 @@ static int batadv_netlink_hardif_put(struct sk_buff *msg, if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL, atomic_read(&hard_iface->bat_v.elp_interval))) goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT_OVERRIDE, + atomic_read(&hard_iface->bat_v.throughput_override))) + goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BATMAN_V */
genlmsg_end(msg, hdr); @@ -923,6 +928,13 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb,
atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr)); } + + if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { + attr = info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]; + + atomic_set(&hard_iface->bat_v.throughput_override, + nla_get_u32(attr)); + } #endif /* CONFIG_BATMAN_ADV_BATMAN_V */
batadv_netlink_notify_hardif(bat_priv, hard_iface);
The generic netlink code is expected to trigger notification messages when configuration might have been changed. But the configuration of batman-adv is most of the time still done using sysfs. So the sysfs interface should also trigger the corresponding netlink messages via the "config" multicast group.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/netlink.c | 10 +++---- net/batman-adv/netlink.h | 6 ++++ net/batman-adv/sysfs.c | 63 +++++++++++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 16 deletions(-)
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 4065d871..37552736 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -383,7 +383,7 @@ static int batadv_netlink_mesh_put(struct sk_buff *msg, * * Return: 0 on success, < 0 on error */ -static int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv) +int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv) { struct sk_buff *msg; int ret; @@ -850,8 +850,8 @@ static int batadv_netlink_hardif_put(struct sk_buff *msg, * * Return: 0 on success, < 0 on error */ -static int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, - struct batadv_hard_iface *hard_iface) +int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface) { struct sk_buff *msg; int ret; @@ -1055,8 +1055,8 @@ static int batadv_netlink_vlan_put(struct sk_buff *msg, * * Return: 0 on success, < 0 on error */ -static int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, - struct batadv_softif_vlan *vlan) +int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, + struct batadv_softif_vlan *vlan) { struct sk_buff *msg; int ret; diff --git a/net/batman-adv/netlink.h b/net/batman-adv/netlink.h index 571d9a5a..8d17ce0e 100644 --- a/net/batman-adv/netlink.h +++ b/net/batman-adv/netlink.h @@ -34,6 +34,12 @@ int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst, u8 result, u32 test_time, u64 total_bytes, u32 cookie);
+int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv); +int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, + struct batadv_hard_iface *hard_iface); +int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, + struct batadv_softif_vlan *vlan); + extern struct genl_family batadv_netlink_family;
#endif /* _NET_BATMAN_ADV_NETLINK_H_ */ diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 344e5787..7c67fe29 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -48,6 +48,7 @@ #include "gateway_common.h" #include "hard-interface.h" #include "log.h" +#include "netlink.h" #include "network-coding.h" #include "soft-interface.h"
@@ -154,9 +155,14 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ { \ struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ struct batadv_priv *bat_priv = netdev_priv(net_dev); \ + ssize_t length; \ + \ + length = __batadv_store_bool_attr(buff, count, _post_func, attr,\ + &bat_priv->_name, net_dev); \ \ - return __batadv_store_bool_attr(buff, count, _post_func, attr, \ - &bat_priv->_name, net_dev); \ + batadv_netlink_notify_mesh(bat_priv); \ + \ + return length; \ }
#define BATADV_ATTR_SIF_SHOW_BOOL(_name) \ @@ -186,11 +192,16 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ { \ struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ struct batadv_priv *bat_priv = netdev_priv(net_dev); \ + ssize_t length; \ \ - return __batadv_store_uint_attr(buff, count, _min, _max, \ - _post_func, attr, \ - &bat_priv->_var, net_dev, \ - NULL); \ + length = __batadv_store_uint_attr(buff, count, _min, _max, \ + _post_func, attr, \ + &bat_priv->_var, net_dev, \ + NULL); \ + \ + batadv_netlink_notify_mesh(bat_priv); \ + \ + return length; \ }
#define BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \ @@ -223,6 +234,11 @@ ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ attr, &vlan->_name, \ bat_priv->soft_iface); \ \ + if (vlan->vid) \ + batadv_netlink_notify_vlan(bat_priv, vlan); \ + else \ + batadv_netlink_notify_mesh(bat_priv); \ + \ batadv_softif_vlan_put(vlan); \ return res; \ } @@ -256,6 +272,7 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ { \ struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ struct batadv_hard_iface *hard_iface; \ + struct batadv_priv *bat_priv; \ ssize_t length; \ \ hard_iface = batadv_hardif_get_by_netdev(net_dev); \ @@ -268,6 +285,11 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ hard_iface->soft_iface, \ net_dev); \ \ + if (hard_iface->soft_iface) { \ + bat_priv = netdev_priv(hard_iface->soft_iface); \ + batadv_netlink_notify_hardif(bat_priv, hard_iface); \ + } \ + \ batadv_hardif_put(hard_iface); \ return length; \ } @@ -537,6 +559,9 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj, batadv_gw_check_client_stop(bat_priv); atomic_set(&bat_priv->gw.mode, (unsigned int)gw_mode_tmp); batadv_gw_tvlv_container_update(bat_priv); + + batadv_netlink_notify_mesh(bat_priv); + return count; }
@@ -563,6 +588,7 @@ static ssize_t batadv_store_gw_sel_class(struct kobject *kobj, size_t count) { struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); + ssize_t length;
/* setting the GW selection class is allowed only if the routing * algorithm in use implements the GW API @@ -578,10 +604,14 @@ static ssize_t batadv_store_gw_sel_class(struct kobject *kobj, return bat_priv->algo_ops->gw.store_sel_class(bat_priv, buff, count);
- return __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE, - batadv_post_gw_reselect, attr, - &bat_priv->gw.sel_class, - bat_priv->soft_iface, NULL); + length = __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE, + batadv_post_gw_reselect, attr, + &bat_priv->gw.sel_class, + bat_priv->soft_iface, NULL); + + batadv_netlink_notify_mesh(bat_priv); + + return length; }
static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, @@ -601,12 +631,18 @@ static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { + struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); struct net_device *net_dev = batadv_kobj_to_netdev(kobj); + ssize_t length;
if (buff[count - 1] == '\n') buff[count - 1] = '\0';
- return batadv_gw_bandwidth_set(net_dev, buff, count); + length = batadv_gw_bandwidth_set(net_dev, buff, count); + + batadv_netlink_notify_mesh(bat_priv); + + return length; }
/** @@ -674,6 +710,8 @@ static ssize_t batadv_store_isolation_mark(struct kobject *kobj, "New skb mark for extended isolation: %#.8x/%#.8x\n", bat_priv->isolation_mark, bat_priv->isolation_mark_mask);
+ batadv_netlink_notify_mesh(bat_priv); + return count; }
@@ -1078,6 +1116,7 @@ static ssize_t batadv_store_throughput_override(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { + struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); struct net_device *net_dev = batadv_kobj_to_netdev(kobj); struct batadv_hard_iface *hard_iface; u32 tp_override; @@ -1108,6 +1147,8 @@ static ssize_t batadv_store_throughput_override(struct kobject *kobj,
atomic_set(&hard_iface->bat_v.throughput_override, tp_override);
+ batadv_netlink_notify_hardif(bat_priv, hard_iface); + out: batadv_hardif_put(hard_iface); return count;
On Fri, Dec 07, 2018 at 02:58:46PM +0100, Sven Eckelmann wrote:
The generic netlink code is expected to trigger notification messages when configuration might have been changed. But the configuration of batman-adv is most of the time still done using sysfs. So the sysfs interface should also trigger the corresponding netlink messages via the "config" multicast group.
Signed-off-by: Sven Eckelmann sven@narfation.org
I'm wondering, before it was quite easy to add new sysfs attributes with just a few lines thanks to macros. Now we need to add code in four more places in netlink.c whenever we introduce a new configuration option.
Would it be possible (and maybe even reduce code size?) if the sysfs and netlink parts were wrapped into some (macro) functions and/or structs, to still be able to add options from a central place and with only a few lines?
Or would that become too ugly? Or not worth the effort for the few options we have right now?
On Friday, 4 January 2019 03.29.16 CET Linus Lüssing wrote: [...]
I'm wondering, before it was quite easy to add new sysfs attributes with just a few lines thanks to macros. Now we need to add code in four more places in netlink.c whenever we introduce a new configuration option.
Would it be possible (and maybe even reduce code size?) if the sysfs and netlink parts were wrapped into some (macro) functions and/or structs, to still be able to add options from a central place and with only a few lines?
Or would that become too ugly? Or not worth the effort for the few options we have right now?
You only need a couple of lines to add netlink things. And we don't want sysfs anymore. So no need to add ugly hacks to add both netlink+sysfs with a "couple of lines".
Kind regards, Sven
On Fri, Jan 04, 2019 at 08:58:32AM +0100, Sven Eckelmann wrote:
On Friday, 4 January 2019 03.29.16 CET Linus Lüssing wrote: [...]
I'm wondering, before it was quite easy to add new sysfs attributes with just a few lines thanks to macros. Now we need to add code in four more places in netlink.c whenever we introduce a new configuration option.
Would it be possible (and maybe even reduce code size?) if the sysfs and netlink parts were wrapped into some (macro) functions and/or structs, to still be able to add options from a central place and with only a few lines?
Or would that become too ugly? Or not worth the effort for the few options we have right now?
You only need a couple of lines to add netlink things. And we don't want sysfs anymore. So no need to add ugly hacks to add both netlink+sysfs with a "couple of lines".
Kind regards, Sven
Ok
b.a.t.m.a.n@lists.open-mesh.org