As mentioned earlier, the netlink config restructuring in batctl will be splitted in multiple steps. The first step was already merged and the RFC changes for the netlink interface in batman-adv were just posted.
The batman-adv weren't directly rejected by Jiro and thus I've started to convert all settings to netlink while still allowing sysfs as fallback.
v4: * last patch (which adds the netlink implementation of the settings commands) was splitted in 16 separate patches * Cc the (most likely) responsible developers for each setting to more directly ask them for feedback v3: * fix kernel-doc in batman_adv.h * add three patches to use the netlink interface with the already existing setting commands v2: * drop of generic config command * reimplementation of the event command
Kind regards, Sven
Sven Eckelmann (20): batctl: Add support for config mcast group in event monitor batctl: Don't allocate new buffer for vlan parent device batctl: Automatically translate vlan to mesh_iface batctl: Add settings_data hooks for netlink integration batctl: Parse the arguments for gw_mode batctl: Add netlink simple query helper batctl: Support generic netlink for gw_mode command batctl: Support generic netlink for loglevel command batctl: Support generic netlink for isolation_mark command batctl: Support generic netlink for orig_interval command batctl: Add helper to read/write boolean configuration values batctl: Support generic netlink for aggregation command batctl: Support generic netlink for ap_isolation command batctl: Support generic netlink for bonding command batctl: Support generic netlink for bridge_loop_avoidance command batctl: Support generic netlink for distributed_arp_table command batctl: Support generic netlink for fragmentation command batctl: Support generic netlink for multicast_mode command batctl: Support generic netlink for network_coding command batctl: Drop settings_date param lists
aggregation.c | 45 ++++- ap_isolation.c | 67 ++++++- batman_adv.h | 188 +++++++++++++++++- bonding.c | 45 ++++- bridge_loop_avoidance.c | 46 ++++- distributed_arp_table.c | 46 ++++- event.c | 234 ++++++++++++++++++++++ fragmentation.c | 45 ++++- functions.c | 160 +++++++++++++--- functions.h | 23 ++- gateways.c | 10 +- gw_mode.c | 416 +++++++++++++++++++++++++++++++--------- isolation_mark.c | 123 +++++++++++- loglevel.c | 138 ++++++++++--- main.c | 10 +- main.h | 6 +- mcast_flags.c | 10 +- multicast_mode.c | 45 ++++- netlink.c | 108 ++++++++++- netlink.h | 2 + network_coding.c | 45 ++++- orig_interval.c | 84 +++++++- originators.c | 10 +- routing_algo.c | 1 - sys.c | 219 ++++++++++++++++----- sys.h | 25 ++- 26 files changed, 1895 insertions(+), 256 deletions(-)
The netlink set netlink messages issued by the config subcommands get as reply a multicast message with the new value. The event monitor should show these messages similar to the tp_meter results.
Signed-off-by: Sven Eckelmann sven@narfation.org --- batman_adv.h | 188 +++++++++++++++++++++++++++++++++++++++-- event.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.c | 20 +++++ 3 files changed, 437 insertions(+), 5 deletions(-)
diff --git a/batman_adv.h b/batman_adv.h index 324a0e1..b5a245e 100644 --- a/batman_adv.h +++ b/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"
/** @@ -138,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 */ @@ -344,6 +359,136 @@ enum batadv_nl_attrs { */ BATADV_ATTR_MCAST_FLAGS_PRIV,
+ /** + * @BATADV_ATTR_VLANID: VLAN id on top of soft interface + */ + 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, + + /** + * @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, + + /** + * @BATADV_ATTR_BONDING: whether the data traffic going through the + * mesh will be sent using multiple interfaces at the same time. + */ + 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, + + /** + * @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, + + /** + * @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, + + /** + * @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, + + /** + * @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, + + /** + * @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, + + /** + * @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, + + /** + * @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, + + /** + * @BATADV_ATTR_ORIG_INTERVAL: defines the interval in milliseconds in + * which batman sends its protocol messages. + */ + 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, + + /** + * @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 */
/** @@ -372,10 +517,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, + + /** + * @BATADV_CMD_GET_MESH_INFO: Alias for @BATADV_CMD_GET_MESH */ - BATADV_CMD_GET_MESH_INFO, + BATADV_CMD_GET_MESH_INFO = BATADV_CMD_GET_MESH,
/** * @BATADV_CMD_TP_METER: Start a tp meter session @@ -393,9 +542,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 @@ -443,6 +598,29 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_MCAST_FLAGS,
+ /** + * @BATADV_CMD_SET_MESH: Set attributes for softif/mesh + */ + BATADV_CMD_SET_MESH, + + /** + * @BATADV_CMD_SET_HARDIF: Set attributes for hardif of the + * current softif + */ + 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/event.c b/event.c index 8eda269..28a5205 100644 --- a/event.c +++ b/event.c @@ -22,6 +22,7 @@
#include <errno.h> #include <getopt.h> +#include <net/if.h> #include <netinet/if_ether.h> #include <netlink/netlink.h> #include <netlink/genl/genl.h> @@ -51,6 +52,14 @@ struct event_args { struct timeval tv; };
+static const char *u8_to_boolstr(struct nlattr *attrs) +{ + if (nla_get_u8(attrs)) + return "true"; + else + return "false"; +} + static void event_usage(void) { fprintf(stderr, "Usage: batctl [options] event [parameters]\n"); @@ -87,6 +96,25 @@ static int event_prepare(struct state *state)
skip_tp_meter:
+ mcid = nl_get_multicast_id(state->sock, BATADV_NL_NAME, + BATADV_NL_MCAST_GROUP_CONFIG); + if (mcid < 0) { + fprintf(stderr, "Failed to resolve batadv config multicast group: %d\n", + mcid); + /* ignore error for now */ + goto skip_config; + } + + ret = nl_socket_add_membership(state->sock, mcid); + if (ret) { + fprintf(stderr, "Failed to join batadv config multicast group: %d\n", + ret); + /* ignore error for now */ + goto skip_config; + } + +skip_config: + return 0; }
@@ -145,6 +173,203 @@ static void event_parse_tp_meter(struct nlattr **attrs) printf("tp_meter 0x%08x: %s\n", cookie, result_str); }
+static void event_parse_set_mesh(struct nlattr **attrs) +{ + static const int mesh_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_ALGO_NAME, + }; + char meshif_buf[IF_NAMESIZE]; + char *meshif_name; + uint32_t mesh_ifindex; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, mesh_mandatory, + ARRAY_SIZE(mesh_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + printf("%s: set mesh:\n", meshif_name); + + if (attrs[BATADV_ATTR_AGGREGATED_OGMS]) + printf("* aggregated_ogms %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AGGREGATED_OGMS])); + + if (attrs[BATADV_ATTR_AP_ISOLATION]) + printf("* ap_isolation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AP_ISOLATION])); + + if (attrs[BATADV_ATTR_ISOLATION_MARK]) + printf("* isolation_mark 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MARK])); + + if (attrs[BATADV_ATTR_ISOLATION_MASK]) + printf("* isolation_mask 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MASK])); + + if (attrs[BATADV_ATTR_BONDING]) + printf("* bonding %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_BONDING])); + + if (attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE]) + printf("* bridge_loop_avoidance %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE])); + + if (attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE]) + printf("* distributed_arp_table %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE])); + + if (attrs[BATADV_ATTR_FRAGMENTATION]) + printf("* fragmentation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_FRAGMENTATION])); + + if (attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]); + printf("* gw_bandwidth_down %u.%01u MBit/s\n", val / 10, + val % 10); + } + + if (attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_UP]); + printf("* gw_bandwidth_up %u.%01u MBit/s\n", val / 10, + val % 10); + } + + if (attrs[BATADV_ATTR_GW_MODE]) { + uint8_t val = nla_get_u8(attrs[BATADV_ATTR_GW_MODE]); + const char *valstr; + + switch (val) { + case BATADV_GW_MODE_OFF: + valstr = "off"; + break; + case BATADV_GW_MODE_CLIENT: + valstr = "client"; + break; + case BATADV_GW_MODE_SERVER: + valstr = "server"; + break; + default: + valstr = "unknown"; + break; + } + + printf("* gw_mode %s\n", valstr); + } + + if (attrs[BATADV_ATTR_GW_SEL_CLASS]) { + uint32_t val = nla_get_u32(attrs[BATADV_ATTR_GW_SEL_CLASS]); + const char *algo = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + + if (strcmp(algo, "BATMAN_V") == 0) + printf("* gw_sel_class %u.%01u MBit/s\n", val / 10, + val % 10); + else + printf("* gw_sel_class %u\n", val); + } + + if (attrs[BATADV_ATTR_HOP_PENALTY]) + printf("* hop_penalty %u\n", + nla_get_u8(attrs[BATADV_ATTR_HOP_PENALTY])); + + if (attrs[BATADV_ATTR_LOG_LEVEL]) + printf("* log_level 0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_LOG_LEVEL])); + + if (attrs[BATADV_ATTR_MULTICAST_MODE]) + printf("* multicast_mode %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_MULTICAST_MODE])); + + if (attrs[BATADV_ATTR_NETWORK_CODING]) + printf("* network_coding %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_NETWORK_CODING])); + + if (attrs[BATADV_ATTR_ORIG_INTERVAL]) + printf("* orig_interval %u ms\n", + nla_get_u32(attrs[BATADV_ATTR_ORIG_INTERVAL])); +} + +static void event_parse_set_hardif(struct nlattr **attrs) +{ + static const int hardif_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_HARD_IFINDEX, + }; + char meshif_buf[IF_NAMESIZE]; + char hardif_buf[IF_NAMESIZE]; + char *meshif_name; + char *hardif_name; + uint32_t hardif_ifindex; + uint32_t mesh_ifindex; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, hardif_mandatory, + ARRAY_SIZE(hardif_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + hardif_ifindex = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + hardif_name = if_indextoname(hardif_ifindex, hardif_buf); + if (!hardif_name) + return; + + printf("%s (%s): set hardif:\n", meshif_name, hardif_name); + + if (attrs[BATADV_ATTR_ELP_INTERVAL]) + printf("* elp_interval %u ms\n", + nla_get_u32(attrs[BATADV_ATTR_ELP_INTERVAL])); + + if (attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { + uint32_t val; + + val = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]); + printf("* throughput_override %u.%01u MBit/s\n", val / 10, + val % 10); + } +} + +static void event_parse_set_vlan(struct nlattr **attrs) +{ + static const int vlan_mandatory[] = { + BATADV_ATTR_MESH_IFINDEX, + BATADV_ATTR_VLANID, + }; + char meshif_buf[IF_NAMESIZE]; + char *meshif_name; + uint32_t mesh_ifindex; + uint16_t vid; + + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, vlan_mandatory, + ARRAY_SIZE(vlan_mandatory))) + return; + + mesh_ifindex = nla_get_u32(attrs[BATADV_ATTR_MESH_IFINDEX]); + meshif_name = if_indextoname(mesh_ifindex, meshif_buf); + if (!meshif_name) + return; + + vid = nla_get_u16(attrs[BATADV_ATTR_VLANID]); + + printf("%s (vid %u): set vlan:\n", meshif_name, vid); + + if (attrs[BATADV_ATTR_AP_ISOLATION]) + printf("* ap_isolation %s\n", + u8_to_boolstr(attrs[BATADV_ATTR_AP_ISOLATION])); +} + static unsigned long long get_timestamp(struct event_args *event_args) { unsigned long long prevtime = 0; @@ -190,6 +415,15 @@ static int event_parse(struct nl_msg *msg, void *arg) case BATADV_CMD_TP_METER: event_parse_tp_meter(attrs); break; + case BATADV_CMD_SET_MESH: + event_parse_set_mesh(attrs); + break; + case BATADV_CMD_SET_HARDIF: + event_parse_set_hardif(attrs); + break; + case BATADV_CMD_SET_VLAN: + event_parse_set_vlan(attrs); + break; default: printf("Received unknown event %u\n", ghdr->cmd); break; diff --git a/netlink.c b/netlink.c index 5285759..1829544 100644 --- a/netlink.c +++ b/netlink.c @@ -107,6 +107,26 @@ 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 }, + [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 }, + [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 }, + [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 }, + [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 }, + [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 }, + [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NLA_U32 }, };
int netlink_create(struct state *state)
The buffer size is limited by IF_NAMESIZE and can easily be stored on the stack. This will also make it easier to store this as part of the the state of batctl.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 23 ++++++----------------- functions.h | 2 +- sys.c | 6 +++--- 3 files changed, 10 insertions(+), 21 deletions(-)
diff --git a/functions.c b/functions.c index bdede8b..ecfd202 100644 --- a/functions.c +++ b/functions.c @@ -830,10 +830,6 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg)
/* get parent link name */ idx = *(int *)nla_data(tb[IFLA_LINK]); - free(nl_arg->iface); - nl_arg->iface = malloc(IFNAMSIZ + 1); - if (!nl_arg->iface) - goto err;
if (!if_indextoname(idx, nl_arg->iface)) goto err; @@ -851,12 +847,12 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg) /** * vlan_get_link - convert a VLAN interface into its parent one * @ifname: the interface to convert - * @parent: buffer where the parent interface name will be written (allocated by - * this function) + * @parent: buffer where the parent interface name will be written + * (minimum IF_NAMESIZE) * * Returns the vlan identifier on success or -1 on error */ -int vlan_get_link(const char *ifname, char **parent) +int vlan_get_link(const char *ifname, char *parent) { struct nl_sock *sock; int ret; @@ -866,12 +862,10 @@ int vlan_get_link(const char *ifname, char **parent) }; struct nl_cb *cb = NULL; struct vlan_get_link_nl_arg arg = { - .iface = NULL, + .iface = parent, .vid = -1, };
- *parent = NULL; - sock = nl_socket_alloc(); if (!sock) goto err; @@ -894,8 +888,6 @@ int vlan_get_link(const char *ifname, char **parent) if (ret < 0) goto err;
- *parent = arg.iface; - err: if (cb) nl_cb_put(cb); @@ -1029,13 +1021,13 @@ int netlink_simple_request(struct nl_msg *msg)
int check_mesh_iface(char *mesh_iface) { - char *base_dev = NULL; char path_buff[PATH_BUFF_LEN]; + char base_dev[IF_NAMESIZE]; int ret = -1, vid; DIR *dir;
/* use the parent interface if this is a VLAN */ - vid = vlan_get_link(mesh_iface, &base_dev); + vid = vlan_get_link(mesh_iface, base_dev); if (vid >= 0) snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); else @@ -1050,9 +1042,6 @@ int check_mesh_iface(char *mesh_iface)
ret = 0; out: - if (base_dev) - free(base_dev); - return ret; }
diff --git a/functions.h b/functions.h index c16ba2e..2680e6d 100644 --- a/functions.h +++ b/functions.h @@ -48,7 +48,7 @@ int write_file(const char *dir, const char *fname, const char *arg1, struct ether_addr *translate_mac(const char *mesh_iface, const struct ether_addr *mac); struct ether_addr *resolve_mac(const char *asc); -int vlan_get_link(const char *ifname, char **parent);\ +int vlan_get_link(const char *ifname, char *parent); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); int check_mesh_iface(char *mesh_iface); diff --git a/sys.c b/sys.c index 6b98ac4..5c54f08 100644 --- a/sys.c +++ b/sys.c @@ -67,7 +67,8 @@ int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; int vid, optchar, res = EXIT_FAILURE; - char *path_buff, *base_dev = NULL; + char base_dev[IF_NAMESIZE]; + char *path_buff; const char **ptr;
while ((optchar = getopt(argc, argv, "h")) != -1) { @@ -93,7 +94,7 @@ int handle_sys_setting(struct state *state, int argc, char **argv) /* if the specified interface is a VLAN then change the path to point * to the proper "vlan%{vid}" subfolder in the sysfs tree. */ - vid = vlan_get_link(state->mesh_iface, &base_dev); + vid = vlan_get_link(state->mesh_iface, base_dev); if (vid >= 0) snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid);
@@ -133,6 +134,5 @@ int handle_sys_setting(struct state *state, int argc, char **argv)
out: free(path_buff); - free(base_dev); return res; }
The way batctl is implementing support for VLANs is rather suboptimal. The program has to guess whether it is started with an batadv or vlan interface as argument.
Instead of distributing this over the whole program, do it on startup and already retrieve the required mesh interface index and vid before the rest of the program runs.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 34 ++++++++++++++++++++++++++-------- functions.h | 6 ++++-- gateways.c | 10 ++-------- main.c | 10 ++++++---- main.h | 6 +++++- mcast_flags.c | 10 ++-------- netlink.c | 12 ++---------- originators.c | 10 ++-------- sys.c | 14 +++++++------- 9 files changed, 56 insertions(+), 56 deletions(-)
diff --git a/functions.c b/functions.c index ecfd202..600c29a 100644 --- a/functions.c +++ b/functions.c @@ -852,7 +852,7 @@ static int vlan_get_link_parse(struct nl_msg *msg, void *arg) * * Returns the vlan identifier on success or -1 on error */ -int vlan_get_link(const char *ifname, char *parent) +static int vlan_get_link(const char *ifname, char *parent) { struct nl_sock *sock; int ret; @@ -1019,19 +1019,33 @@ int netlink_simple_request(struct nl_msg *msg) return err; }
-int check_mesh_iface(char *mesh_iface) +int translate_mesh_iface(struct state *state) +{ + state->vid = vlan_get_link(state->arg_iface, state->mesh_iface); + if (state->vid < 0) { + /* if there is no iface then the argument must be the + * mesh interface + */ + snprintf(state->mesh_iface, sizeof(state->mesh_iface), "%s", + state->arg_iface); + } + + return 0; +} + +int check_mesh_iface(struct state *state) { char path_buff[PATH_BUFF_LEN]; - char base_dev[IF_NAMESIZE]; - int ret = -1, vid; + int ret = -1; DIR *dir;
/* use the parent interface if this is a VLAN */ - vid = vlan_get_link(mesh_iface, base_dev); - if (vid >= 0) - snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); + if (state->vid >= 0) + snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, + state->mesh_iface, state->vid); else - snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, mesh_iface); + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, + state->mesh_iface);
/* try to open the mesh sys directory */ dir = opendir(path_buff); @@ -1040,6 +1054,10 @@ int check_mesh_iface(char *mesh_iface)
closedir(dir);
+ state->mesh_ifindex = if_nametoindex(state->mesh_iface); + if (state->mesh_ifindex == 0) + goto out; + ret = 0; out: return ret; diff --git a/functions.h b/functions.h index 2680e6d..ea3c307 100644 --- a/functions.h +++ b/functions.h @@ -34,6 +34,8 @@
#define PATH_BUFF_LEN 400
+struct state; + /* return time delta from start to end in milliseconds */ void start_timer(void); double end_timer(void); @@ -48,10 +50,10 @@ int write_file(const char *dir, const char *fname, const char *arg1, struct ether_addr *translate_mac(const char *mesh_iface, const struct ether_addr *mac); struct ether_addr *resolve_mac(const char *asc); -int vlan_get_link(const char *ifname, char *parent); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); -int check_mesh_iface(char *mesh_iface); +int translate_mesh_iface(struct state *state); +int check_mesh_iface(struct state *state); int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
void get_random_bytes(void *buf, size_t buflen); diff --git a/gateways.c b/gateways.c index ff7693f..5beddc7 100644 --- a/gateways.c +++ b/gateways.c @@ -133,17 +133,11 @@ static int netlink_print_gateways(struct state *state, char *orig_iface, { char *header = NULL; char *info_header; - int ifindex; - - ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - }
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0) diff --git a/main.c b/main.c index ab7da45..37a2b5a 100644 --- a/main.c +++ b/main.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) { const struct command *cmd; struct state state = { - .mesh_iface = mesh_dfl_iface, + .arg_iface = mesh_dfl_iface, .cmd = NULL, }; int opt; @@ -138,13 +138,13 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); break; case 'm': - if (state.mesh_iface != mesh_dfl_iface) { + if (state.arg_iface != mesh_dfl_iface) { fprintf(stderr, "Error - multiple mesh interfaces specified\n"); goto err; }
- state.mesh_iface = argv[2]; + state.arg_iface = argv[2]; break; case 'v': version(); @@ -173,8 +173,10 @@ int main(int argc, char **argv)
state.cmd = cmd;
+ translate_mesh_iface(&state); + if (cmd->flags & COMMAND_FLAG_MESH_IFACE && - check_mesh_iface(state.mesh_iface) < 0) { + check_mesh_iface(&state) < 0) { fprintf(stderr, "Error - interface %s is not present or not a batman-adv interface\n", state.mesh_iface); diff --git a/main.h b/main.h index 276a018..274fae5 100644 --- a/main.h +++ b/main.h @@ -25,6 +25,7 @@
#include <stdint.h>
+#include <net/if.h> #include <netlink/genl/ctrl.h> #include <netlink/genl/genl.h> #include <netlink/netlink.h> @@ -74,7 +75,10 @@ enum command_type { };
struct state { - char *mesh_iface; + char *arg_iface; + char mesh_iface[IF_NAMESIZE]; + unsigned int mesh_ifindex; + int vid; const struct command *cmd;
struct nl_sock *sock; diff --git a/mcast_flags.c b/mcast_flags.c index 0dc4227..eb9734e 100644 --- a/mcast_flags.c +++ b/mcast_flags.c @@ -113,17 +113,11 @@ static int netlink_print_mcast_flags(struct state *state, char *orig_iface, char *info_header; char *header; bool bridged; - int ifindex; int ret;
- ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - } - /* only parse own multicast flags */ - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_MCAST_FLAGS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_MCAST_FLAGS, NULL); free(info_header);
if (mcast_flags == -EOPNOTSUPP || mcast_flags_priv == -EOPNOTSUPP) diff --git a/netlink.c b/netlink.c index 1829544..b0d57b1 100644 --- a/netlink.c +++ b/netlink.c @@ -443,20 +443,12 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, }; int hardifindex = 0; struct nl_msg *msg; - int ifindex;
if (!state->sock) { last_err = -EOPNOTSUPP; return last_err; }
- ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - last_err = -ENODEV; - return last_err; - } - if (orig_iface) { hardifindex = if_nametoindex(orig_iface); if (!hardifindex) { @@ -479,7 +471,7 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, printf("\033[2J\033[0;0f");
if (!(read_opt & SKIP_HEADER)) - opts.remaining_header = netlink_get_info(ifindex, + opts.remaining_header = netlink_get_info(state->mesh_ifindex, nl_cmd, header);
@@ -490,7 +482,7 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, NLM_F_DUMP, nl_cmd, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); if (hardifindex) nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hardifindex); diff --git a/originators.c b/originators.c index c29300a..3c13c66 100644 --- a/originators.c +++ b/originators.c @@ -185,17 +185,11 @@ static int netlink_print_originators(struct state *state, char *orig_iface, { char *header = NULL; char *info_header; - int ifindex; - - ifindex = if_nametoindex(state->mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", state->mesh_iface); - return -ENODEV; - }
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(ifindex, BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state->mesh_ifindex, + BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0) diff --git a/sys.c b/sys.c index 5c54f08..be20be7 100644 --- a/sys.c +++ b/sys.c @@ -66,8 +66,7 @@ static void settings_usage(struct state *state) int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; - int vid, optchar, res = EXIT_FAILURE; - char base_dev[IF_NAMESIZE]; + int optchar, res = EXIT_FAILURE; char *path_buff; const char **ptr;
@@ -89,14 +88,15 @@ int handle_sys_setting(struct state *state, int argc, char **argv) return EXIT_FAILURE; }
- snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); - /* if the specified interface is a VLAN then change the path to point * to the proper "vlan%{vid}" subfolder in the sysfs tree. */ - vid = vlan_get_link(state->mesh_iface, base_dev); - if (vid >= 0) - snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, base_dev, vid); + if (state->vid >= 0) + snprintf(path_buff, PATH_BUFF_LEN, SYS_VLAN_PATH, + state->mesh_iface, state->vid); + else + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, + state->mesh_iface);
if (argc == 1) { res = read_file(path_buff, settings->sysfs_name,
The generic netlink infrastructure will be used in the future to replace sysfs for manipulating the runtime configuation of batman-adv meshifs, hardifs and vlans. These will not use the raw strings when communicating with the kernel interface but a well defined binary message format.
This means that the read function for settings must parse the binary format and convert it to a textual representation for the user. The netlink_get hook of struct settings_data will be used for that.
A similar problem is the setting of configuration entries. The textual representation of the user input has to be parsed and validated. And the resulting attributes have to be put in a message which the kernel can interpret. The parsing is done in the parse hook which can use the data pointer to store the results. The netlink_set hook has to prepare the generic netlink message and send it to the kernel.
Signed-off-by: Sven Eckelmann sven@narfation.org --- sys.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- sys.h | 4 ++++ 2 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/sys.c b/sys.c index be20be7..e883369 100644 --- a/sys.c +++ b/sys.c @@ -63,6 +63,47 @@ static void settings_usage(struct state *state) fprintf(stderr, " \t -h print this help\n"); }
+static int sys_read_setting(struct state *state, const char *path_buff, + const char *sysfs_name) +{ + struct settings_data *settings = state->cmd->arg; + int res = EXIT_FAILURE; + + if (settings->netlink_get) { + res = settings->netlink_get(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + } + + if (sysfs_name) + res = read_file(path_buff, sysfs_name, NO_FLAGS, 0, 0, 0); + + return res; +} + +static int sys_write_setting(struct state *state, const char *path_buff, + const char *sysfs_name, int argc, char **argv) +{ + struct settings_data *settings = state->cmd->arg; + int res = EXIT_FAILURE; + + if (settings->netlink_set) { + res = settings->netlink_set(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + } + + if (sysfs_name) + res = write_file(path_buff, sysfs_name, + argv[1], argc > 2 ? argv[2] : NULL); + + return res; +} + int handle_sys_setting(struct state *state, int argc, char **argv) { struct settings_data *settings = state->cmd->arg; @@ -99,13 +140,20 @@ int handle_sys_setting(struct state *state, int argc, char **argv) state->mesh_iface);
if (argc == 1) { - res = read_file(path_buff, settings->sysfs_name, - NO_FLAGS, 0, 0, 0); + res = sys_read_setting(state, path_buff, settings->sysfs_name); goto out; }
check_root_or_die("batctl");
+ if (settings->parse) { + res = settings->parse(state, argc, argv); + if (res < 0) { + res = EXIT_FAILURE; + goto out; + } + } + if (!settings->params) goto write_file;
@@ -129,8 +177,8 @@ int handle_sys_setting(struct state *state, int argc, char **argv) goto out;
write_file: - res = write_file(path_buff, settings->sysfs_name, - argv[1], argc > 2 ? argv[2] : NULL); + res = sys_write_setting(state, path_buff, settings->sysfs_name, argc, + argv);
out: free(path_buff); diff --git a/sys.h b/sys.h index 20e1934..cac2c53 100644 --- a/sys.h +++ b/sys.h @@ -42,6 +42,10 @@ struct settings_data { const char *sysfs_name; const char **params; + void *data; + int (*parse)(struct state *state, int argc, char *argv[]); + int (*netlink_get)(struct state *state); + int (*netlink_set)(struct state *state); };
extern const char *sysfs_param_enable[];
The generic netlink interface requires that the configuration settings are parsed in userspace. But it can also be used to do a more fine grained validation of the input data before it is written to the sysfs files.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch Cc: Antonio Quartulli a@unstable.cc --- functions.c | 92 ++++++++++++++++++++++++++ functions.h | 16 +++++ gw_mode.c | 171 +++++++++++++++++++++++++++++++++++++++---------- netlink.c | 76 ++++++++++++++++++++++ netlink.h | 2 + routing_algo.c | 1 - sys.c | 7 -- sys.h | 2 +- 8 files changed, 324 insertions(+), 43 deletions(-)
diff --git a/functions.c b/functions.c index 600c29a..ead7e97 100644 --- a/functions.c +++ b/functions.c @@ -499,6 +499,44 @@ struct ether_addr *translate_mac(const char *mesh_iface, return mac_result; }
+int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len) +{ + char *path_buff; + int ret; + + ret = get_algoname_netlink(mesh_iface, algoname, algoname_len); + if (ret != -EOPNOTSUPP) + return ret; + + path_buff = malloc(PATH_BUFF_LEN); + if (!path_buff) { + fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + return -ENOMEM; + } + + snprintf(path_buff, PATH_BUFF_LEN, SYS_ROUTING_ALGO_FMT, mesh_iface); + ret = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0); + if (ret != EXIT_SUCCESS) { + ret = -ENOENT; + goto free_path_buf; + } + + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0'; + + strncpy(algoname, line_ptr, algoname_len); + if (algoname_len > 0) + algoname[algoname_len - 1] = '\0'; + +free_path_buf: + free(path_buff); + + free(line_ptr); + line_ptr = NULL; + + return ret; +} + static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) { int ret; @@ -1162,3 +1200,57 @@ void check_root_or_die(const char *cmd) exit(EXIT_FAILURE); } } + +bool parse_throughput(char *buff, const char *description, uint32_t *throughput) +{ + enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; + uint64_t lthroughput; + char *tmp_ptr; + char *endptr; + + if (strlen(buff) > 4) { + tmp_ptr = buff + strlen(buff) - 4; + + if (strncasecmp(tmp_ptr, "mbit", 4) == 0) + bw_unit_type = BATADV_BW_UNIT_MBIT; + + if (strncasecmp(tmp_ptr, "kbit", 4) == 0 || + bw_unit_type == BATADV_BW_UNIT_MBIT) + *tmp_ptr = '\0'; + } + + lthroughput = strtoull(buff, &endptr, 10); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Invalid throughput speed for %s: %s\n", + description, buff); + return false; + } + + switch (bw_unit_type) { + case BATADV_BW_UNIT_MBIT: + /* prevent overflow */ + if (UINT64_MAX / 10 < lthroughput) { + fprintf(stderr, + "Throughput speed for %s too large: %s\n", + description, buff); + return false; + } + + lthroughput *= 10; + break; + case BATADV_BW_UNIT_KBIT: + default: + lthroughput = lthroughput / 100; + break; + } + + if (lthroughput > UINT32_MAX) { + fprintf(stderr, "Throughput speed for %s too large: %s\n", + description, buff); + return false; + } + + *throughput = lthroughput; + + return true; +} diff --git a/functions.h b/functions.h index ea3c307..4a6ab61 100644 --- a/functions.h +++ b/functions.h @@ -26,8 +26,20 @@ #include <net/ethernet.h> #include <netlink/netlink.h> #include <netlink/handlers.h> +#include <stdbool.h> #include <stddef.h> +#include <stdint.h>
+/** + * enum batadv_bandwidth_units - bandwidth unit types + */ +enum batadv_bandwidth_units { + /** @BATADV_BW_UNIT_KBIT: unit type kbit */ + BATADV_BW_UNIT_KBIT, + + /** @BATADV_BW_UNIT_MBIT: unit type mbit */ + BATADV_BW_UNIT_MBIT, +};
#define ETH_STR_LEN 17 #define BATMAN_ADV_TAG "batman-adv:" @@ -53,12 +65,16 @@ struct ether_addr *resolve_mac(const char *asc); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); int netlink_simple_request(struct nl_msg *msg); int translate_mesh_iface(struct state *state); +int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len); int check_mesh_iface(struct state *state); int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface);
void get_random_bytes(void *buf, size_t buflen); void check_root_or_die(const char *cmd);
+bool parse_throughput(char *buff, const char *description, + uint32_t *throughput); + extern char *line_ptr;
enum { diff --git a/gw_mode.c b/gw_mode.c index 4093f89..167b777 100644 --- a/gw_mode.c +++ b/gw_mode.c @@ -20,23 +20,33 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <getopt.h> +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
+#include "batman_adv.h" #include "functions.h" +#include "main.h" +#include "netlink.h" #include "sys.h"
#define SYS_GW_MODE "gw_mode" #define SYS_GW_SEL "gw_sel_class" #define SYS_GW_BW "gw_bandwidth"
-enum gw_modes { - GW_MODE_OFF, - GW_MODE_CLIENT, - GW_MODE_SERVER, -}; +static struct gw_data { + uint8_t bandwidth_down_found:1; + uint8_t bandwidth_up_found:1; + uint8_t sel_class_found:1; + uint8_t mode; + uint32_t bandwidth_down; + uint32_t bandwidth_up; + uint32_t sel_class; +} gw_globals;
static void gw_mode_usage(void) { @@ -45,11 +55,117 @@ static void gw_mode_usage(void) fprintf(stderr, " \t -h print this help\n"); }
+static bool is_throughput_select_class(struct state *state) +{ + char algoname[32]; + int ret; + + ret = get_algoname(state->mesh_iface, algoname, sizeof(algoname)); + + /* no algo name -> assume that it is a pre-B.A.T.M.A.N. V version */ + if (ret < 0) + return false; + + if (strcmp(algoname, "BATMAN_V") == 0) + return true; + + return false; +} +static int parse_gw_limit(char *buff) +{ + char *slash_ptr; + bool ret; + + slash_ptr = strchr(buff, '/'); + if (slash_ptr) + *slash_ptr = 0; + + ret = parse_throughput(buff, "download gateway speed", + &gw_globals.bandwidth_down); + if (!ret) + return -EINVAL; + + gw_globals.bandwidth_down_found = 1; + + /* we also got some upload info */ + if (slash_ptr) { + ret = parse_throughput(slash_ptr + 1, "upload gateway speed", + &gw_globals.bandwidth_up); + if (!ret) + return -EINVAL; + + gw_globals.bandwidth_up_found = 1; + } + + return 0; +} + +static int parse_gw(struct state *state, int argc, char *argv[]) +{ + char buff[256]; + char *endptr; + int ret; + + if (argc != 2 && argc != 3) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1/2)\n"); + return -EINVAL; + } + + if (strcmp(argv[1], "client") == 0) { + gw_globals.mode = BATADV_GW_MODE_CLIENT; + } else if (strcmp(argv[1], "server") == 0) { + gw_globals.mode = BATADV_GW_MODE_SERVER; + } else if (strcmp(argv[1], "off") == 0) { + gw_globals.mode = BATADV_GW_MODE_OFF; + } else { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + fprintf(stderr, "The following values are allowed:\n"); + fprintf(stderr, " * off\n"); + fprintf(stderr, " * client\n"); + fprintf(stderr, " * server\n"); + + return -EINVAL; + } + + if (argc <= 2) + return 0; + + strncpy(buff, argv[2], sizeof(buff)); + buff[sizeof(buff) - 1] = '\0'; + + switch (gw_globals.mode) { + case BATADV_GW_MODE_OFF: + fprintf(stderr, "Error - unexpected argument for mode "off": %s\n", argv[2]); + return -EINVAL; + case BATADV_GW_MODE_CLIENT: + if (is_throughput_select_class(state)) { + if (!parse_throughput(buff, "sel_class", + &gw_globals.sel_class)) + return -EINVAL; + } else { + gw_globals.sel_class = strtoul(buff, &endptr, 0); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Error - unexpected argument for mode "client": %s\n", buff); + return -EINVAL; + } + } + + gw_globals.sel_class_found = 1; + break; + case BATADV_GW_MODE_SERVER: + ret = parse_gw_limit(buff); + if (ret < 0) + return ret; + break; + } + + return 0; +} + static int gw_mode(struct state *state, int argc, char **argv) { int optchar, res = EXIT_FAILURE; char *path_buff, gw_mode; - const char **ptr;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -80,20 +196,20 @@ static int gw_mode(struct state *state, int argc, char **argv) line_ptr[strlen(line_ptr) - 1] = '\0';
if (strcmp(line_ptr, "client") == 0) - gw_mode = GW_MODE_CLIENT; + gw_mode = BATADV_GW_MODE_CLIENT; else if (strcmp(line_ptr, "server") == 0) - gw_mode = GW_MODE_SERVER; + gw_mode = BATADV_GW_MODE_SERVER; else - gw_mode = GW_MODE_OFF; + gw_mode = BATADV_GW_MODE_OFF;
free(line_ptr); line_ptr = NULL;
switch (gw_mode) { - case GW_MODE_CLIENT: + case BATADV_GW_MODE_CLIENT: res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0); break; - case GW_MODE_SERVER: + case BATADV_GW_MODE_SERVER: res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0); break; default: @@ -108,10 +224,10 @@ static int gw_mode(struct state *state, int argc, char **argv) line_ptr[strlen(line_ptr) - 1] = '\0';
switch (gw_mode) { - case GW_MODE_CLIENT: + case BATADV_GW_MODE_CLIENT: printf("client (selection class: %s)\n", line_ptr); break; - case GW_MODE_SERVER: + case BATADV_GW_MODE_SERVER: printf("server (announced bw: %s)\n", line_ptr); break; default: @@ -125,14 +241,11 @@ static int gw_mode(struct state *state, int argc, char **argv)
check_root_or_die("batctl gw_mode");
- if (strcmp(argv[1], "client") == 0) - gw_mode = GW_MODE_CLIENT; - else if (strcmp(argv[1], "server") == 0) - gw_mode = GW_MODE_SERVER; - else if (strcmp(argv[1], "off") == 0) - gw_mode = GW_MODE_OFF; - else - goto opt_err; + res = parse_gw(state, argc, argv); + if (res < 0) { + res = EXIT_FAILURE; + goto out; + }
res = write_file(path_buff, SYS_GW_MODE, argv[1], NULL); if (res != EXIT_SUCCESS) @@ -141,27 +254,17 @@ static int gw_mode(struct state *state, int argc, char **argv) if (argc == 2) goto out;
- switch (gw_mode) { - case GW_MODE_CLIENT: + switch (gw_globals.mode) { + case BATADV_GW_MODE_CLIENT: res = write_file(path_buff, SYS_GW_SEL, argv[2], NULL); break; - case GW_MODE_SERVER: + case BATADV_GW_MODE_SERVER: res = write_file(path_buff, SYS_GW_BW, argv[2], NULL); break; }
goto out;
-opt_err: - fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); - fprintf(stderr, "The following values are allowed:\n"); - - ptr = sysfs_param_server; - while (*ptr) { - fprintf(stderr, " * %s\n", *ptr); - ptr++; - } - out: free(path_buff); return res; diff --git a/netlink.c b/netlink.c index b0d57b1..9c29774 100644 --- a/netlink.c +++ b/netlink.c @@ -853,3 +853,79 @@ int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac)
return 0; } + +struct get_algoname_netlink_opts { + char *algoname; + size_t algoname_len; + bool found; + struct nlquery_opts query_opts; +}; + +static int get_algoname_netlink_cb(struct nl_msg *msg, void *arg) +{ + static const int mandatory[] = { + BATADV_ATTR_ALGO_NAME, + }; + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlquery_opts *query_opts = arg; + struct get_algoname_netlink_opts *opts; + struct genlmsghdr *ghdr; + const char *algoname; + + opts = container_of(query_opts, struct get_algoname_netlink_opts, + query_opts); + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_MESH) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (missing_mandatory_attrs(attrs, mandatory, ARRAY_SIZE(mandatory))) + return NL_OK; + + algoname = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + + /* save result */ + strncpy(opts->algoname, algoname, opts->algoname_len); + if (opts->algoname_len > 0) + opts->algoname[opts->algoname_len - 1] = '\0'; + + opts->found = true; + opts->query_opts.err = 0; + + return NL_STOP; +} + +int get_algoname_netlink(const char *mesh_iface, char *algoname, + size_t algoname_len) +{ + struct get_algoname_netlink_opts opts = { + .algoname = algoname, + .algoname_len = algoname_len, + .found = false, + .query_opts = { + .err = 0, + }, + }; + int ret; + + ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_MESH, + get_algoname_netlink_cb, 0, + &opts.query_opts); + if (ret < 0) + return ret; + + if (!opts.found) + return -EOPNOTSUPP; + + return 0; +} diff --git a/netlink.h b/netlink.h index b91ca10..9be49cd 100644 --- a/netlink.h +++ b/netlink.h @@ -50,6 +50,8 @@ int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, uint8_t *nexthop, char *ifname); int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac); +int get_algoname_netlink(const char *mesh_iface, char *algoname, + size_t algoname_len);
extern struct nla_policy batadv_netlink_policy[];
diff --git a/routing_algo.c b/routing_algo.c index 18d9ef7..69eac34 100644 --- a/routing_algo.c +++ b/routing_algo.c @@ -41,7 +41,6 @@ #include "sys.h"
#define SYS_SELECTED_RA_PATH "/sys/module/batman_adv/parameters/routing_algo" -#define SYS_ROUTING_ALGO_FMT SYS_IFACE_PATH"/%s/mesh/routing_algo"
static void ra_mode_usage(void) { diff --git a/sys.c b/sys.c index e883369..482daed 100644 --- a/sys.c +++ b/sys.c @@ -47,13 +47,6 @@ const char *sysfs_param_enable[] = { NULL, };
-const char *sysfs_param_server[] = { - "off", - "client", - "server", - NULL, -}; - static void settings_usage(struct state *state) { fprintf(stderr, "Usage: batctl [options] %s|%s [parameters] %s\n", diff --git a/sys.h b/sys.h index cac2c53..1c8f23d 100644 --- a/sys.h +++ b/sys.h @@ -37,6 +37,7 @@ #define SYS_MESH_IFACE_FMT SYS_IFACE_PATH"/%s/batman_adv/mesh_iface" #define SYS_IFACE_STATUS_FMT SYS_IFACE_PATH"/%s/batman_adv/iface_status" #define SYS_VLAN_PATH SYS_IFACE_PATH"/%s/mesh/vlan%d/" +#define SYS_ROUTING_ALGO_FMT SYS_IFACE_PATH"/%s/mesh/routing_algo" #define VLAN_ID_MAX_LEN 4
struct settings_data { @@ -49,7 +50,6 @@ struct settings_data { };
extern const char *sysfs_param_enable[]; -extern const char *sysfs_param_server[];
int handle_sys_setting(struct state *state, int argc, char **argv);
All functions which will use the new configuration interface for meshifs, hardifs and vlans require a simple method to send messages and have one or multiple extra functionality:
* add special attributes (attribute_cb) * return errors which happened during communication via netlink * parse the reply message (callback)
The sys_simple_nlquery provides this but requires that the netlink socket and the single use nl_cb was allocated by the initialization helper via COMMAND_FLAG_MESH_IFACE.
Signed-off-by: Sven Eckelmann sven@narfation.org --- sys.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sys.h | 10 ++++++++++ 2 files changed, 69 insertions(+)
diff --git a/sys.c b/sys.c index 482daed..a44502c 100644 --- a/sys.c +++ b/sys.c @@ -47,6 +47,65 @@ const char *sysfs_param_enable[] = { NULL, };
+static int sys_simple_nlerror(struct sockaddr_nl *nla __maybe_unused, + struct nlmsgerr *nlerr, void *arg) +{ + int *result = arg; + + if (nlerr->error != -EOPNOTSUPP) + fprintf(stderr, "Error received: %s\n", + strerror(-nlerr->error)); + + *result = nlerr->error; + + return NL_STOP; +} + +int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t attribute_cb, + nl_recvmsg_msg_cb_t callback) +{ + int result; + struct nl_msg *msg; + int ret; + + if (!state->sock) + return -EOPNOTSUPP; + + if (callback) { + result = -EOPNOTSUPP; + nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, callback, + &result); + } else { + result = 0; + } + + nl_cb_err(state->cb, NL_CB_CUSTOM, sys_simple_nlerror, &result); + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, + nl_cmd, 1); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); + + if (attribute_cb) { + ret = attribute_cb(msg, state); + if (ret < 0) { + nlmsg_free(msg); + return -ENOMEM; + } + } + + nl_send_auto_complete(state->sock, msg); + nlmsg_free(msg); + + nl_recvmsgs(state->sock, state->cb); + + return result; +} + static void settings_usage(struct state *state) { fprintf(stderr, "Usage: batctl [options] %s|%s [parameters] %s\n", diff --git a/sys.h b/sys.h index 1c8f23d..57224d5 100644 --- a/sys.h +++ b/sys.h @@ -25,6 +25,12 @@
#include "main.h"
+#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" + #define SYS_BATIF_PATH_FMT "/sys/class/net/%s/mesh/" #define SYS_LOG_LEVEL "log_level" #define SYS_LOG "log" @@ -53,4 +59,8 @@ extern const char *sysfs_param_enable[];
int handle_sys_setting(struct state *state, int argc, char **argv);
+int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t attribute_cb, + nl_recvmsg_msg_cb_t callback); + #endif
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The gw_mode implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH 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 - 1-255 for BATMAN_IV - 1-UINT32_MAX for BATMAN_V
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch Cc: Antonio Quartulli a@unstable.cc --- gw_mode.c | 275 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 206 insertions(+), 69 deletions(-)
diff --git a/gw_mode.c b/gw_mode.c index 167b777..477a1ff 100644 --- a/gw_mode.c +++ b/gw_mode.c @@ -162,80 +162,233 @@ static int parse_gw(struct state *state, int argc, char *argv[]) return 0; }
-static int gw_mode(struct state *state, int argc, char **argv) +static int print_gw(struct nl_msg *msg, void *arg) { - int optchar, res = EXIT_FAILURE; - char *path_buff, gw_mode; + static const int mandatory[] = { + BATADV_ATTR_GW_MODE, + }; + static const int mandatory_client[] = { + BATADV_ATTR_ALGO_NAME, + BATADV_ATTR_GW_SEL_CLASS, + }; + static const int mandatory_server[] = { + BATADV_ATTR_GW_BANDWIDTH_DOWN, + BATADV_ATTR_GW_BANDWIDTH_UP, + }; + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + const char *algo; + uint8_t gw_mode; + uint32_t val; + uint32_t down; + uint32_t up; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + }
- while ((optchar = getopt(argc, argv, "h")) != -1) { - switch (optchar) { - case 'h': - gw_mode_usage(); - return EXIT_SUCCESS; - default: - gw_mode_usage(); - return EXIT_FAILURE; - } + /* ignore entry when attributes are missing */ + if (missing_mandatory_attrs(attrs, mandatory, ARRAY_SIZE(mandatory))) + return NL_OK; + + gw_mode = nla_get_u8(attrs[BATADV_ATTR_GW_MODE]); + switch (gw_mode) { + case BATADV_GW_MODE_OFF: + printf("off\n"); + break; + case BATADV_GW_MODE_CLIENT: + if (missing_mandatory_attrs(attrs, mandatory_client, + ARRAY_SIZE(mandatory_client))) + return NL_OK; + + algo = nla_data(attrs[BATADV_ATTR_ALGO_NAME]); + val = nla_get_u32(attrs[BATADV_ATTR_GW_SEL_CLASS]); + + if (strcmp(algo, "BATMAN_V") == 0) + printf("client (selection class: %u.%01u MBit)\n", + val / 10, val % 10); + else + printf("client (selection class: %u)\n", val); + break; + case BATADV_GW_MODE_SERVER: + if (missing_mandatory_attrs(attrs, mandatory_server, + ARRAY_SIZE(mandatory_server))) + return NL_OK; + + down = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]); + up = nla_get_u32(attrs[BATADV_ATTR_GW_BANDWIDTH_UP]); + + printf("server (announced bw: %u.%01u/%u.%01u MBit)\n", + down / 10, down % 10, up / 10, up % 10); + break; + default: + printf("unknown\n"); + break; }
- path_buff = malloc(PATH_BUFF_LEN); - if (!path_buff) { - fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + *result = 0; + return NL_STOP; +} + +static int get_gw(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, NULL, print_gw); +} + +static int set_attrs_gw(struct nl_msg *msg, void *arg __maybe_unused) +{ + nla_put_u8(msg, BATADV_ATTR_GW_MODE, gw_globals.mode); + + if (gw_globals.bandwidth_down_found) + nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, + gw_globals.bandwidth_down); + + if (gw_globals.bandwidth_up_found) + nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, + gw_globals.bandwidth_up); + + if (gw_globals.sel_class_found) + nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, + gw_globals.sel_class); + + return 0; +} + +static int set_gw(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, set_attrs_gw, + NULL); +} + +static int gw_read_setting(struct state *state, const char *path_buff) +{ + enum batadv_gw_modes gw_mode; + int res; + + res = get_gw(state); + if (res < 0 && res != -EOPNOTSUPP) return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + /* fallback to sysfs */ + res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0, 0); + if (res != EXIT_SUCCESS) + goto out; + + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0'; + + if (strcmp(line_ptr, "client") == 0) + gw_mode = BATADV_GW_MODE_CLIENT; + else if (strcmp(line_ptr, "server") == 0) + gw_mode = BATADV_GW_MODE_SERVER; + else + gw_mode = BATADV_GW_MODE_OFF; + + free(line_ptr); + line_ptr = NULL; + + switch (gw_mode) { + case BATADV_GW_MODE_CLIENT: + res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0); + break; + case BATADV_GW_MODE_SERVER: + res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0); + break; + default: + printf("off\n"); + goto out; }
- snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); + if (res != EXIT_SUCCESS) + goto out;
- if (argc == 1) { - res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0, 0); + if (line_ptr[strlen(line_ptr) - 1] == '\n') + line_ptr[strlen(line_ptr) - 1] = '\0';
- if (res != EXIT_SUCCESS) - goto out; + switch (gw_mode) { + case BATADV_GW_MODE_CLIENT: + printf("client (selection class: %s)\n", line_ptr); + break; + case BATADV_GW_MODE_SERVER: + printf("server (announced bw: %s)\n", line_ptr); + break; + default: + goto out; + }
- if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; +out: + free(line_ptr); + line_ptr = NULL;
- if (strcmp(line_ptr, "client") == 0) - gw_mode = BATADV_GW_MODE_CLIENT; - else if (strcmp(line_ptr, "server") == 0) - gw_mode = BATADV_GW_MODE_SERVER; - else - gw_mode = BATADV_GW_MODE_OFF; + return res; +} + +static int gw_write_setting(struct state *state, const char *path_buff, + int argc, char *argv[]) +{ + int res = EXIT_FAILURE; + + res = set_gw(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS;
- free(line_ptr); - line_ptr = NULL; + /* sysfs fallback */ + res = write_file(path_buff, SYS_GW_MODE, argv[1], NULL); + if (res != EXIT_SUCCESS) + return res;
- switch (gw_mode) { + if (argc > 2) { + switch (gw_globals.mode) { case BATADV_GW_MODE_CLIENT: - res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0); + res = write_file(path_buff, SYS_GW_SEL, argv[2], NULL); break; case BATADV_GW_MODE_SERVER: - res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0); + res = write_file(path_buff, SYS_GW_BW, argv[2], NULL); break; - default: - printf("off\n"); - goto out; } + }
- if (res != EXIT_SUCCESS) - goto out; + return res; +}
- if (line_ptr[strlen(line_ptr) - 1] == '\n') - line_ptr[strlen(line_ptr) - 1] = '\0'; +static int gw_mode(struct state *state, int argc, char **argv) +{ + int optchar, res = EXIT_FAILURE; + char *path_buff;
- switch (gw_mode) { - case BATADV_GW_MODE_CLIENT: - printf("client (selection class: %s)\n", line_ptr); - break; - case BATADV_GW_MODE_SERVER: - printf("server (announced bw: %s)\n", line_ptr); - break; + while ((optchar = getopt(argc, argv, "h")) != -1) { + switch (optchar) { + case 'h': + gw_mode_usage(); + return EXIT_SUCCESS; default: - goto out; + gw_mode_usage(); + return EXIT_FAILURE; } + }
- free(line_ptr); - line_ptr = NULL; + path_buff = malloc(PATH_BUFF_LEN); + if (!path_buff) { + fprintf(stderr, "Error - could not allocate path buffer: out of memory ?\n"); + return EXIT_FAILURE; + } + + snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, state->mesh_iface); + + if (argc == 1) { + res = gw_read_setting(state, path_buff); goto out; }
@@ -247,28 +400,12 @@ static int gw_mode(struct state *state, int argc, char **argv) goto out; }
- res = write_file(path_buff, SYS_GW_MODE, argv[1], NULL); - if (res != EXIT_SUCCESS) - goto out; - - if (argc == 2) - goto out; - - switch (gw_globals.mode) { - case BATADV_GW_MODE_CLIENT: - res = write_file(path_buff, SYS_GW_SEL, argv[2], NULL); - break; - case BATADV_GW_MODE_SERVER: - res = write_file(path_buff, SYS_GW_BW, argv[2], NULL); - break; - } - - goto out; - + res = gw_write_setting(state, path_buff, argc, argv); out: free(path_buff); return res; }
-COMMAND(SUBCOMMAND, gw_mode, "gw", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND, gw_mode, "gw", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "[mode] \tdisplay or modify the gateway mode");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The loglevel implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH 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 --- loglevel.c | 138 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 110 insertions(+), 28 deletions(-)
diff --git a/loglevel.c b/loglevel.c index fed70c8..72e16e0 100644 --- a/loglevel.c +++ b/loglevel.c @@ -20,7 +20,9 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <getopt.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -29,6 +31,10 @@ #include "main.h" #include "sys.h"
+static struct log_level_data { + uint32_t log_level; +} log_level_globals; + static void log_level_usage(void) { fprintf(stderr, "Usage: batctl [options] loglevel [parameters] [level[ level[ level]]...]\n"); @@ -47,14 +53,93 @@ static void log_level_usage(void) fprintf(stderr, " \t tp Messages related to throughput meter\n"); }
+static int extract_log_level(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_LOG_LEVEL]) + return NL_OK; + + log_level_globals.log_level = nla_get_u32(attrs[BATADV_ATTR_LOG_LEVEL]); + + *result = 0; + return NL_STOP; +} + +static int get_log_level(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, extract_log_level); +} + +static int set_attrs_log_level(struct nl_msg *msg, void *arg __maybe_unused) +{ + nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, log_level_globals.log_level); + + return 0; +} + +static int set_log_level(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_log_level, NULL); +} + +static int log_level_read_setting(struct state *state, const char *path_buff) +{ + int res; + + res = get_log_level(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0); + if (res != EXIT_SUCCESS) + return res; + + log_level_globals.log_level = strtol(line_ptr, (char **) NULL, 10); + + return res; +} + +static int log_level_write_setting(struct state *state, const char *path_buff) +{ + int res; + char str[4]; + + res = set_log_level(state); + if (res < 0 && res != -EOPNOTSUPP) + return EXIT_FAILURE; + if (res >= 0) + return EXIT_SUCCESS; + + snprintf(str, sizeof(str), "%i", log_level_globals.log_level); + return write_file(path_buff, SYS_LOG_LEVEL, str, NULL); +} + static int loglevel(struct state *state, int argc, char **argv) { int optchar, res = EXIT_FAILURE; - int log_level = 0; char *path_buff; - char str[4]; int i;
+ log_level_globals.log_level = 0; + while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { case 'h': @@ -79,63 +164,59 @@ static int loglevel(struct state *state, int argc, char **argv)
for (i = 1; i < argc; i++) { if (strcmp(argv[i], "none") == 0) { - log_level = 0; + log_level_globals.log_level = 0; break; } else if (strcmp(argv[i], "all") == 0) { - log_level = 255; + log_level_globals.log_level = 255; break; } else if (strcmp(argv[i], "batman") == 0) - log_level |= BIT(0); + log_level_globals.log_level |= BIT(0); else if (strcmp(argv[i], "routes") == 0) - log_level |= BIT(1); + log_level_globals.log_level |= BIT(1); else if (strcmp(argv[i], "tt") == 0) - log_level |= BIT(2); + log_level_globals.log_level |= BIT(2); else if (strcmp(argv[i], "bla") == 0) - log_level |= BIT(3); + log_level_globals.log_level |= BIT(3); else if (strcmp(argv[i], "dat") == 0) - log_level |= BIT(4); + log_level_globals.log_level |= BIT(4); else if (strcmp(argv[i], "nc") == 0) - log_level |= BIT(5); + log_level_globals.log_level |= BIT(5); else if (strcmp(argv[i], "mcast") == 0) - log_level |= BIT(6); + log_level_globals.log_level |= BIT(6); else if (strcmp(argv[i], "tp") == 0) - log_level |= BIT(7); + log_level_globals.log_level |= BIT(7); else { log_level_usage(); goto out; } }
- snprintf(str, sizeof(str), "%i", log_level); - res = write_file(path_buff, SYS_LOG_LEVEL, str, NULL); + log_level_write_setting(state, path_buff); goto out; }
- res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0); - + res = log_level_read_setting(state, path_buff); if (res != EXIT_SUCCESS) goto out;
- log_level = strtol(line_ptr, (char **) NULL, 10); - - printf("[%c] %s (%s)\n", (!log_level) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (!log_level_globals.log_level) ? 'x' : ' ', "all debug output disabled", "none"); - printf("[%c] %s (%s)\n", (log_level & BIT(0)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(0)) ? 'x' : ' ', "messages related to routing / flooding / broadcasting", "batman"); - printf("[%c] %s (%s)\n", (log_level & BIT(1)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(1)) ? 'x' : ' ', "messages related to route added / changed / deleted", "routes"); - printf("[%c] %s (%s)\n", (log_level & BIT(2)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(2)) ? 'x' : ' ', "messages related to translation table operations", "tt"); - printf("[%c] %s (%s)\n", (log_level & BIT(3)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(3)) ? 'x' : ' ', "messages related to bridge loop avoidance", "bla"); - printf("[%c] %s (%s)\n", (log_level & BIT(4)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(4)) ? 'x' : ' ', "messages related to arp snooping and distributed arp table", "dat"); - printf("[%c] %s (%s)\n", (log_level & BIT(5)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(5)) ? 'x' : ' ', "messages related to network coding", "nc"); - printf("[%c] %s (%s)\n", (log_level & BIT(6)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(6)) ? 'x' : ' ', "messages related to multicast", "mcast"); - printf("[%c] %s (%s)\n", (log_level & BIT(7)) ? 'x' : ' ', + printf("[%c] %s (%s)\n", (log_level_globals.log_level & BIT(7)) ? 'x' : ' ', "messages related to throughput meter", "tp");
out: @@ -143,5 +224,6 @@ static int loglevel(struct state *state, int argc, char **argv) return res; }
-COMMAND(SUBCOMMAND, loglevel, "ll", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND, loglevel, "ll", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "[level] \tdisplay or modify the log level");
On Fri, Dec 07, 2018 at 09:31:57PM +0100, Sven Eckelmann wrote:
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The loglevel implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH 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
loglevel.c | 138 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 110 insertions(+), 28 deletions(-)
diff --git a/loglevel.c b/loglevel.c index fed70c8..72e16e0 100644 --- a/loglevel.c +++ b/loglevel.c @@ -20,7 +20,9 @@
- License-Filename: LICENSES/preferred/GPL-2.0
*/
+#include <errno.h> #include <getopt.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -29,6 +31,10 @@ #include "main.h" #include "sys.h"
+static struct log_level_data {
- uint32_t log_level;
+} log_level_globals;
static void log_level_usage(void) {
Seems that this patch needs a rebase now, after f11e64ac9 ("batctl: Remove check of compiled_out files"). Otherwise I get a conflict with "git am --3way".
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The isolation_mark implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of 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 --- isolation_mark.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-)
diff --git a/isolation_mark.c b/isolation_mark.c index 13ba869..461053f 100644 --- a/isolation_mark.c +++ b/isolation_mark.c @@ -20,16 +20,135 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <stddef.h> +#include <stdint.h> +#include <string.h>
#include "main.h" #include "sys.h"
+static struct isolation_mark_data { + uint32_t isolation_mark; + uint32_t isolation_mask; +} isolation_mark; + +static int parse_isolation_mark(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct isolation_mark_data *data = settings->data; + char *mask_ptr; + char buff[256]; + uint32_t mark; + uint32_t mask; + char *endptr; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + strncpy(buff, argv[1], sizeof(buff)); + buff[sizeof(buff) - 1] = '\0'; + + /* parse the mask if it has been specified, otherwise assume the mask is + * the biggest possible + */ + mask = 0xFFFFFFFF; + mask_ptr = strchr(buff, '/'); + if (mask_ptr) { + *mask_ptr = '\0'; + mask_ptr++; + + /* the mask must be entered in hex base as it is going to be a + * bitmask and not a prefix length + */ + mask = strtoul(mask_ptr, &endptr, 16); + if (!endptr || *endptr != '\0') + goto inval_format; + } + + /* the mark can be entered in any base */ + mark = strtoul(buff, &endptr, 0); + if (!endptr || *endptr != '\0') + goto inval_format; + + data->isolation_mask = mask; + /* erase bits not covered by the mask */ + data->isolation_mark = mark & mask; + + return 0; + +inval_format: + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + fprintf(stderr, "The following formats for mark(/mask) are allowed:\n"); + fprintf(stderr, " * 0x12345678\n"); + fprintf(stderr, " * 0x12345678/0xabcdef09\n"); + return -EINVAL; +} + +static int print_isolation_mark(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_ISOLATION_MARK] || + !attrs[BATADV_ATTR_ISOLATION_MASK]) + return NL_OK; + + printf("0x%08x/0x%08x\n", + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MARK]), + nla_get_u32(attrs[BATADV_ATTR_ISOLATION_MASK])); + + *result = 0; + return NL_STOP; +} + +static int get_isolation_mark(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_isolation_mark); +} + +static int set_attrs_isolation_mark(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct isolation_mark_data *data = settings->data; + + nla_put_u32(msg, BATADV_ATTR_ISOLATION_MARK, data->isolation_mark); + nla_put_u32(msg, BATADV_ATTR_ISOLATION_MASK, data->isolation_mask); + + return 0; +} + +static int set_isolation_mark(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_isolation_mark, NULL); +} + static struct settings_data batctl_settings_isolation_mark = { .sysfs_name = "isolation_mark", - .params = NULL, + .data = &isolation_mark, + .parse = parse_isolation_mark, + .netlink_get = get_isolation_mark, + .netlink_set = set_isolation_mark, };
COMMAND_NAMED(SUBCOMMAND, isolation_mark, "mark", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_isolation_mark, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_isolation_mark, "[mark] \tdisplay or modify isolation_mark setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The orig_interval implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u32 BATADV_ATTR_ORIG_INTERVAL attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch --- orig_interval.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-)
diff --git a/orig_interval.c b/orig_interval.c index d308ea2..6dd0039 100644 --- a/orig_interval.c +++ b/orig_interval.c @@ -20,16 +20,96 @@ * License-Filename: LICENSES/preferred/GPL-2.0 */
+#include <errno.h> #include <stddef.h> +#include <stdint.h> +#include <string.h>
#include "main.h" #include "sys.h"
+static struct orig_interval_data { + uint32_t orig_interval; +} orig_interval; + +static int parse_orig_interval(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct orig_interval_data *data = settings->data; + char *endptr; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + data->orig_interval = strtoul(argv[1], &endptr, 0); + if (!endptr || *endptr != '\0') { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + return -EINVAL; + } + + return 0; +} + +static int print_orig_interval(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (!attrs[BATADV_ATTR_ORIG_INTERVAL]) + return NL_OK; + + printf("%u\n", nla_get_u32(attrs[BATADV_ATTR_ORIG_INTERVAL])); + + *result = 0; + return NL_STOP; +} + +static int get_orig_interval(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_orig_interval); +} + +static int set_attrs_orig_interval(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct orig_interval_data *data = settings->data; + + nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, data->orig_interval); + + return 0; +} + +static int set_orig_interval(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_orig_interval, NULL); +} + static struct settings_data batctl_settings_orig_interval = { .sysfs_name = "orig_interval", - .params = NULL, + .data = &orig_interval, + .parse = parse_orig_interval, + .netlink_get = get_orig_interval, + .netlink_set = set_orig_interval, };
COMMAND_NAMED(SUBCOMMAND, orig_interval, "it", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_orig_interval, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_orig_interval, "[interval] \tdisplay or modify orig_interval setting");
Most of the available settings commands in batctl only operate on a single boolean value. Both the reading, parsing and writing of these values can mostly be handled by the same set of helper functions. Only the actual setting/getting of the correct attribute has to be handled by the actual settings command implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 17 +++++++++++++++++ functions.h | 1 + sys.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sys.h | 8 ++++++++ 4 files changed, 81 insertions(+)
diff --git a/functions.c b/functions.c index ead7e97..bb6dc31 100644 --- a/functions.c +++ b/functions.c @@ -1201,6 +1201,23 @@ void check_root_or_die(const char *cmd) } }
+int parse_bool(const char *val, bool *res) +{ + if (strcasecmp(val, "0") == 0 || + strcasecmp(val, "disable") == 0 || + strcasecmp(val, "disabled") == 0) { + *res = false; + return 0; + } else if (strcasecmp(val, "1") == 0 || + strcasecmp(val, "enable") == 0 || + strcasecmp(val, "enabled") == 0) { + *res = true; + return 0; + } + + return -EINVAL; +} + bool parse_throughput(char *buff, const char *description, uint32_t *throughput) { enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; diff --git a/functions.h b/functions.h index 4a6ab61..5f39104 100644 --- a/functions.h +++ b/functions.h @@ -72,6 +72,7 @@ int check_mesh_iface_ownership(char *mesh_iface, char *hard_iface); void get_random_bytes(void *buf, size_t buflen); void check_root_or_die(const char *cmd);
+int parse_bool(const char *val, bool *res); bool parse_throughput(char *buff, const char *description, uint32_t *throughput);
diff --git a/sys.c b/sys.c index a44502c..ede8b09 100644 --- a/sys.c +++ b/sys.c @@ -47,6 +47,34 @@ const char *sysfs_param_enable[] = { NULL, };
+int parse_simple_boolean(struct state *state, int argc, char *argv[]) +{ + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + int ret; + + if (argc != 2) { + fprintf(stderr, "Error - incorrect number of arguments (expected 1)\n"); + return -EINVAL; + } + + ret = parse_bool(argv[1], &data->val); + if (ret < 0) { + fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); + fprintf(stderr, "The following values are allowed:\n"); + fprintf(stderr, " * 0\n"); + fprintf(stderr, " * disable\n"); + fprintf(stderr, " * disabled\n"); + fprintf(stderr, " * 1\n"); + fprintf(stderr, " * enable\n"); + fprintf(stderr, " * enabled\n"); + + return ret; + } + + return 0; +} + static int sys_simple_nlerror(struct sockaddr_nl *nla __maybe_unused, struct nlmsgerr *nlerr, void *arg) { @@ -106,6 +134,33 @@ int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, return result; }
+int sys_simple_print_boolean(struct nl_msg *msg, void *arg, + enum batadv_nl_attrs attr) +{ + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *ghdr; + int *result = arg; + + if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + + ghdr = nlmsg_data(nlh); + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + return NL_OK; + } + + if (!attrs[attr]) + return NL_OK; + + printf("%s\n", nla_get_u8(attrs[attr]) ? "enabled" : "disabled"); + + *result = 0; + return NL_STOP; +} + static void settings_usage(struct state *state) { fprintf(stderr, "Usage: batctl [options] %s|%s [parameters] %s\n", diff --git a/sys.h b/sys.h index 57224d5..f32f134 100644 --- a/sys.h +++ b/sys.h @@ -27,6 +27,7 @@
#include <linux/genetlink.h> #include <netlink/genl/genl.h> +#include <stdbool.h>
#include "batman_adv.h" #include "netlink.h" @@ -57,10 +58,17 @@ struct settings_data {
extern const char *sysfs_param_enable[];
+struct simple_boolean_data { + bool val; +}; + int handle_sys_setting(struct state *state, int argc, char **argv); +int parse_simple_boolean(struct state *state, int argc, char *argv[]);
int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, nl_recvmsg_msg_cb_t attribute_cb, nl_recvmsg_msg_cb_t callback); +int sys_simple_print_boolean(struct nl_msg *msg, void *arg, + enum batadv_nl_attrs attr);
#endif
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The aggregation implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_AGGREGATED_OGMS attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Marek Lindner mareklindner@neomailbox.ch --- aggregation.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/aggregation.c b/aggregation.c index 57c1dbb..fa6610c 100644 --- a/aggregation.c +++ b/aggregation.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data aggregated_ogms; + +static int print_aggregated_ogms(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_AGGREGATED_OGMS); +} + +static int get_aggregated_ogms(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_aggregated_ogms); +} + +static int set_attrs_aggregated_ogms(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS, data->val); + + return 0; +} + +static int set_aggregated_ogms(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_aggregated_ogms, NULL); +} + static struct settings_data batctl_settings_aggregation = { .sysfs_name = "aggregated_ogms", - .params = sysfs_param_enable, + .data = &aggregated_ogms, + .parse = parse_simple_boolean, + .netlink_get = get_aggregated_ogms, + .netlink_set = set_aggregated_ogms, };
COMMAND_NAMED(SUBCOMMAND, aggregation, "ag", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_aggregation, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_aggregation, "[0|1] \tdisplay or modify aggregation setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The ap_isolation implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH and BATADV_CMD_SET_VLAN/BATADV_CMD_GET_VLAN to set/get the configuration of the u8 (boolean) BATADV_ATTR_AP_ISOLATION attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Antonio Quartulli a@unstable.cc --- ap_isolation.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/ap_isolation.c b/ap_isolation.c index 2d16c68..c9fd336 100644 --- a/ap_isolation.c +++ b/ap_isolation.c @@ -21,13 +21,76 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data ap_isolation; + +static int print_ap_isolation(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_AP_ISOLATION); +} + +static int get_attrs_ap_isolation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + + if (state->vid >= 0) + nla_put_u16(msg, BATADV_ATTR_VLANID, state->vid); + + return 0; +} + +static int get_ap_isolation(struct state *state) +{ + enum batadv_nl_commands nl_cmd = BATADV_CMD_SET_MESH; + + if (state->vid >= 0) + nl_cmd = BATADV_CMD_GET_VLAN; + + return sys_simple_nlquery(state, nl_cmd, get_attrs_ap_isolation, + print_ap_isolation); +} + +static int set_attrs_ap_isolation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION, data->val); + + if (state->vid >= 0) + nla_put_u16(msg, BATADV_ATTR_VLANID, state->vid); + + return 0; +} + +static int set_ap_isolation(struct state *state) +{ + enum batadv_nl_commands nl_cmd = BATADV_CMD_SET_MESH; + + if (state->vid >= 0) + nl_cmd = BATADV_CMD_SET_VLAN; + + return sys_simple_nlquery(state, nl_cmd, set_attrs_ap_isolation, NULL); +} + static struct settings_data batctl_settings_ap_isolation = { .sysfs_name = "ap_isolation", - .params = sysfs_param_enable, + .data = &ap_isolation, + .parse = parse_simple_boolean, + .netlink_get = get_ap_isolation, + .netlink_set = set_ap_isolation, };
COMMAND_NAMED(SUBCOMMAND, ap_isolation, "ap", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_ap_isolation, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_ap_isolation, "[0|1] \tdisplay or modify ap_isolation setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The bonding implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_BONDING attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Simon Wunderlich sw@simonwunderlich.de --- bonding.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/bonding.c b/bonding.c index f7105c9..3b8b11b 100644 --- a/bonding.c +++ b/bonding.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data bonding; + +static int print_bonding(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_BONDING); +} + +static int get_bonding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_bonding); +} + +static int set_attrs_bonding(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_BONDING, data->val); + + return 0; +} + +static int set_bonding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_bonding, NULL); +} + static struct settings_data batctl_settings_bonding = { .sysfs_name = "bonding", - .params = sysfs_param_enable, + .data = &bonding, + .parse = parse_simple_boolean, + .netlink_get = get_bonding, + .netlink_set = set_bonding, };
COMMAND_NAMED(SUBCOMMAND, bonding, "b", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_bonding, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_bonding, "[0|1] \tdisplay or modify bonding setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The bridge_loop_avoidance implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Simon Wunderlich sw@simonwunderlich.de --- bridge_loop_avoidance.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c index 0db49f2..7831a19 100644 --- a/bridge_loop_avoidance.c +++ b/bridge_loop_avoidance.c @@ -21,13 +21,55 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data bridge_loop_avoidance; + +static int print_bridge_loop_avoidance(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, + BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE); +} + +static int get_bridge_loop_avoidance(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_bridge_loop_avoidance); +} + +static int set_attrs_bridge_loop_avoidance(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE, data->val); + + return 0; +} + +static int set_bridge_loop_avoidance(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_bridge_loop_avoidance, NULL); +} + static struct settings_data batctl_settings_bridge_loop_avoidance = { .sysfs_name = SYS_BLA, - .params = sysfs_param_enable, + .data = &bridge_loop_avoidance, + .parse = parse_simple_boolean, + .netlink_get = get_bridge_loop_avoidance, + .netlink_set = set_bridge_loop_avoidance, };
COMMAND_NAMED(SUBCOMMAND, bridge_loop_avoidance, "bl", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_bridge_loop_avoidance, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_bridge_loop_avoidance, "[0|1] \tdisplay or modify bridge_loop_avoidance setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The distributed_arp_table implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_DISTRIBUTED_ARP_TABLE attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Antonio Quartulli a@unstable.cc --- distributed_arp_table.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/distributed_arp_table.c b/distributed_arp_table.c index ba6e5b7..ab3da32 100644 --- a/distributed_arp_table.c +++ b/distributed_arp_table.c @@ -21,13 +21,55 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data distributed_arp_table; + +static int print_distributed_arp_table(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, + BATADV_ATTR_DISTRIBUTED_ARP_TABLE); +} + +static int get_distributed_arp_table(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_distributed_arp_table); +} + +static int set_attrs_distributed_arp_table(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE, data->val); + + return 0; +} + +static int set_distributed_arp_table(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_distributed_arp_table, NULL); +} + static struct settings_data batctl_settings_distributed_arp_table = { .sysfs_name = SYS_DAT, - .params = sysfs_param_enable, + .data = &distributed_arp_table, + .parse = parse_simple_boolean, + .netlink_get = get_distributed_arp_table, + .netlink_set = set_distributed_arp_table, };
COMMAND_NAMED(SUBCOMMAND, distributed_arp_table, "dat", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_distributed_arp_table, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_distributed_arp_table, "[0|1] \tdisplay or modify distributed_arp_table setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The fragmentation implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_FRAGMENTATION attribute.
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 --- fragmentation.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/fragmentation.c b/fragmentation.c index e159bdd..7f5f488 100644 --- a/fragmentation.c +++ b/fragmentation.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data fragmentation; + +static int print_fragmentation(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_FRAGMENTATION); +} + +static int get_fragmentation(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_fragmentation); +} + +static int set_attrs_fragmentation(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION, data->val); + + return 0; +} + +static int set_fragmentation(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_fragmentation, NULL); +} + static struct settings_data batctl_settings_fragmentation = { .sysfs_name = "fragmentation", - .params = sysfs_param_enable, + .data = &fragmentation, + .parse = parse_simple_boolean, + .netlink_get = get_fragmentation, + .netlink_set = set_fragmentation, };
COMMAND_NAMED(SUBCOMMAND, fragmentation, "f", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_fragmentation, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_fragmentation, "[0|1] \tdisplay or modify fragmentation setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The multicast_mode implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_MULTICAST_MODE attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Linus Lüssing linus.luessing@c0d3.blue --- multicast_mode.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/multicast_mode.c b/multicast_mode.c index 8542928..381b8a6 100644 --- a/multicast_mode.c +++ b/multicast_mode.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data multicast_mode; + +static int print_multicast_mode(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_MULTICAST_MODE); +} + +static int get_multicast_mode(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_multicast_mode); +} + +static int set_attrs_multicast_mode(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_MULTICAST_MODE, data->val); + + return 0; +} + +static int set_multicast_mode(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_multicast_mode, NULL); +} + static struct settings_data batctl_settings_multicast_mode = { .sysfs_name = SYS_MULTICAST_MODE, - .params = sysfs_param_enable, + .data = &multicast_mode, + .parse = parse_simple_boolean, + .netlink_get = get_multicast_mode, + .netlink_set = set_multicast_mode, };
COMMAND_NAMED(SUBCOMMAND, multicast_mode, "mm", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_multicast_mode, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_multicast_mode, "[0|1] \tdisplay or modify multicast_mode setting");
sysfs should be avoided for new settings of network interfaces. To still provide a common configuration infrastructure, all the existing settings subcommands also have to be reimplemented via generic netlink while still using sysfs as fallback.
The network_coding implementation is using the commands BATADV_CMD_SET_MESH/BATADV_CMD_GET_MESH to set/get the configuration of the u8 (boolean) BATADV_ATTR_NETWORK_CODING attribute.
Signed-off-by: Sven Eckelmann sven@narfation.org --- Cc: Martin Hundeboll martin@hundeboll.net Cc: Marek Lindner mareklindner@neomailbox.ch --- network_coding.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/network_coding.c b/network_coding.c index a4c4296..1dc23ef 100644 --- a/network_coding.c +++ b/network_coding.c @@ -21,13 +21,54 @@ */
#include "main.h" + +#include <errno.h> +#include <linux/genetlink.h> +#include <netlink/genl/genl.h> + +#include "batman_adv.h" +#include "netlink.h" #include "sys.h"
+static struct simple_boolean_data network_coding; + +static int print_network_coding(struct nl_msg *msg, void *arg) +{ + return sys_simple_print_boolean(msg, arg, BATADV_ATTR_NETWORK_CODING); +} + +static int get_network_coding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_GET_MESH, + NULL, print_network_coding); +} + +static int set_attrs_network_coding(struct nl_msg *msg, void *arg) +{ + struct state *state = arg; + struct settings_data *settings = state->cmd->arg; + struct simple_boolean_data *data = settings->data; + + nla_put_u8(msg, BATADV_ATTR_NETWORK_CODING, data->val); + + return 0; +} + +static int set_network_coding(struct state *state) +{ + return sys_simple_nlquery(state, BATADV_CMD_SET_MESH, + set_attrs_network_coding, NULL); +} + static struct settings_data batctl_settings_network_coding = { .sysfs_name = SYS_NETWORK_CODING, - .params = sysfs_param_enable, + .data = &network_coding, + .parse = parse_simple_boolean, + .netlink_get = get_network_coding, + .netlink_set = set_network_coding, };
COMMAND_NAMED(SUBCOMMAND, network_coding, "nc", handle_sys_setting, - COMMAND_FLAG_MESH_IFACE, &batctl_settings_network_coding, + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, + &batctl_settings_network_coding, "[0|1] \tdisplay or modify network_coding setting");
The parsing and validation of the settings command parameters is handled by the parse function. The params struct member is therefore no longer used and can just be dropped.
Signed-off-by: Sven Eckelmann sven@narfation.org --- sys.c | 32 -------------------------------- sys.h | 3 --- 2 files changed, 35 deletions(-)
diff --git a/sys.c b/sys.c index ede8b09..a53b419 100644 --- a/sys.c +++ b/sys.c @@ -39,14 +39,6 @@ #include "functions.h" #include "debug.h"
-const char *sysfs_param_enable[] = { - "enable", - "disable", - "1", - "0", - NULL, -}; - int parse_simple_boolean(struct state *state, int argc, char *argv[]) { struct settings_data *settings = state->cmd->arg; @@ -216,7 +208,6 @@ int handle_sys_setting(struct state *state, int argc, char **argv) struct settings_data *settings = state->cmd->arg; int optchar, res = EXIT_FAILURE; char *path_buff; - const char **ptr;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -261,29 +252,6 @@ int handle_sys_setting(struct state *state, int argc, char **argv) } }
- if (!settings->params) - goto write_file; - - ptr = settings->params; - while (*ptr) { - if (strcmp(*ptr, argv[1]) == 0) - goto write_file; - - ptr++; - } - - fprintf(stderr, "Error - the supplied argument is invalid: %s\n", argv[1]); - fprintf(stderr, "The following values are allowed:\n"); - - ptr = settings->params; - while (*ptr) { - fprintf(stderr, " * %s\n", *ptr); - ptr++; - } - - goto out; - -write_file: res = sys_write_setting(state, path_buff, settings->sysfs_name, argc, argv);
diff --git a/sys.h b/sys.h index f32f134..e7d227d 100644 --- a/sys.h +++ b/sys.h @@ -49,15 +49,12 @@
struct settings_data { const char *sysfs_name; - const char **params; void *data; int (*parse)(struct state *state, int argc, char *argv[]); int (*netlink_get)(struct state *state); int (*netlink_set)(struct state *state); };
-extern const char *sysfs_param_enable[]; - struct simple_boolean_data { bool val; };
On Fri, Dec 07, 2018 at 09:31:49PM +0100, Sven Eckelmann wrote:
As mentioned earlier, the netlink config restructuring in batctl will be splitted in multiple steps. The first step was already merged and the RFC changes for the netlink interface in batman-adv were just posted.
The batman-adv weren't directly rejected by Jiro and thus I've started to convert all settings to netlink while still allowing sysfs as fallback.
Is "batctl if" supposed to use netlink to get the interface status yet?
Currently, with the items in *_attr[] in sysfs.c in batman-adv commented out, I get these errors:
--- root@Linus-Debian:~# batctl if ens3: <error reading status> ens5: <error reading status> ---
On Monday, 7 January 2019 19.57.13 CET Linus Lüssing wrote: [...]
Is "batctl if" supposed to use netlink to get the interface status yet?
Currently, with the items in *_attr[] in sysfs.c in batman-adv commented out, I get these errors:
root@Linus-Debian:~# batctl if ens3: <error reading status> ens5: <error reading status>
Not yet, but I think we should switch to it in the near future.
Kind regards, Sven
b.a.t.m.a.n@lists.open-mesh.org