batctl currently supports settings which are either mesh interface or vlan specific. But B.A.T.M.A.N. V introduced two additional settings which are hard (slave) interface specific. To support these, an additional command prefix called hardif is implemented for some sysfs commands: $ batctl -m bat0 hardif eth0 .. The usable commands with that are: * elp_interval * throughput_override Signed-off-by: Sven Eckelmann <sven@narfation.org>
324 lines
9.3 KiB
Diff
324 lines
9.3 KiB
Diff
From: Sven Eckelmann <sven@narfation.org>
|
|
Date: Thu, 13 Jun 2019 21:12:14 +0200
|
|
Subject: batctl: Make vlan setting explicit
|
|
|
|
The requirement to have a VLAN master device on top of the batadv mesh
|
|
interface is artificially limiting the capabilities of batctl. Not all
|
|
master devices in linux which register a VLAN are from type "vlan" and are
|
|
only registering a single VLAN.
|
|
|
|
For example VLAN aware bridges can create multiple VLANs. These require
|
|
that the VLAN is identified using the VID and not the vlan device.
|
|
|
|
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
|
|
|
Forwarded: https://patchwork.open-mesh.org/patch/17947/
|
|
|
|
diff --git a/ap_isolation.c b/ap_isolation.c
|
|
index 71dcd00eac845d488c4969b17e1339f181c6c913..7c34649225dcc9cc557cc5bb4cbfa2343f8c0763 100644
|
|
--- a/ap_isolation.c
|
|
+++ b/ap_isolation.c
|
|
@@ -81,3 +81,8 @@ COMMAND_NAMED(SUBCOMMAND, ap_isolation, "ap", handle_sys_setting,
|
|
COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK,
|
|
&batctl_settings_ap_isolation,
|
|
"[0|1] \tdisplay or modify ap_isolation setting");
|
|
+
|
|
+COMMAND_NAMED(SUBCOMMAND_VID, ap_isolation, "ap", handle_sys_setting,
|
|
+ COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK,
|
|
+ &batctl_settings_ap_isolation,
|
|
+ "[0|1] \tdisplay or modify ap_isolation setting for vlan device or id");
|
|
diff --git a/main.c b/main.c
|
|
index 278683c6080e3ff4a9f3225931d0c5eb44f89595..6ca13ac0ec4c82ee969be04737a339fd702b52bd 100644
|
|
--- a/main.c
|
|
+++ b/main.c
|
|
@@ -28,48 +28,75 @@ extern const struct command *__stop___command[];
|
|
|
|
static void print_usage(void)
|
|
{
|
|
- enum command_type type[] = {
|
|
- SUBCOMMAND,
|
|
- DEBUGTABLE,
|
|
+ struct {
|
|
+ const char *label;
|
|
+ uint32_t types;
|
|
+ } type[] = {
|
|
+ {
|
|
+ .label = "commands:\n",
|
|
+ .types = BIT(SUBCOMMAND) |
|
|
+ BIT(SUBCOMMAND_VID),
|
|
+ },
|
|
+ {
|
|
+ .label = "debug tables: \tdisplay the corresponding debug table\n",
|
|
+ .types = BIT(DEBUGTABLE),
|
|
+ },
|
|
+ };
|
|
+ const char *default_prefixes[] = {
|
|
+ "",
|
|
+ NULL,
|
|
+ };
|
|
+ const char *vlan_prefixes[] = {
|
|
+ "vlan <vdev> ",
|
|
+ "vid <vid> ",
|
|
+ NULL,
|
|
};
|
|
const struct command **p;
|
|
- char buf[32];
|
|
+ const char **prefixes;
|
|
+ const char **prefix;
|
|
+ char buf[64];
|
|
size_t i;
|
|
|
|
fprintf(stderr, "Usage: batctl [options] command|debug table [parameters]\n");
|
|
fprintf(stderr, "options:\n");
|
|
- fprintf(stderr, " \t-m mesh interface or VLAN created on top of a mesh interface (default 'bat0')\n");
|
|
+ fprintf(stderr, " \t-m mesh interface (default 'bat0')\n");
|
|
fprintf(stderr, " \t-h print this help (or 'batctl <command|debug table> -h' for the parameter help)\n");
|
|
fprintf(stderr, " \t-v print version\n");
|
|
|
|
for (i = 0; i < sizeof(type) / sizeof(*type); i++) {
|
|
fprintf(stderr, "\n");
|
|
|
|
- switch (type[i]) {
|
|
- case SUBCOMMAND:
|
|
- fprintf(stderr, "commands:\n");
|
|
- break;
|
|
- case DEBUGTABLE:
|
|
- fprintf(stderr, "debug tables: \tdisplay the corresponding debug table\n");
|
|
- break;
|
|
- }
|
|
+ fprintf(stderr, "%s", type[i].label);
|
|
|
|
for (p = __start___command; p < __stop___command; p++) {
|
|
const struct command *cmd = *p;
|
|
|
|
- if (cmd->type != type[i])
|
|
+ if (!(BIT(cmd->type) & type[i].types))
|
|
continue;
|
|
|
|
if (!cmd->usage)
|
|
continue;
|
|
|
|
- if (strcmp(cmd->name, cmd->abbr) == 0)
|
|
- snprintf(buf, sizeof(buf), "%s", cmd->name);
|
|
- else
|
|
- snprintf(buf, sizeof(buf), "%s|%s", cmd->name,
|
|
- cmd->abbr);
|
|
+ switch (cmd->type) {
|
|
+ case SUBCOMMAND_VID:
|
|
+ prefixes = vlan_prefixes;
|
|
+ break;
|
|
+ default:
|
|
+ prefixes = default_prefixes;
|
|
+ break;
|
|
+ }
|
|
|
|
- fprintf(stderr, " \t%-27s%s\n", buf, cmd->usage);
|
|
+ for (prefix = &prefixes[0]; *prefix; prefix++) {
|
|
+ if (strcmp(cmd->name, cmd->abbr) == 0)
|
|
+ snprintf(buf, sizeof(buf), "%s%s",
|
|
+ *prefix, cmd->name);
|
|
+ else
|
|
+ snprintf(buf, sizeof(buf), "%s%s|%s",
|
|
+ *prefix, cmd->name, cmd->abbr);
|
|
+
|
|
+ fprintf(stderr, " \t%-35s%s\n", buf,
|
|
+ cmd->usage);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -93,13 +120,19 @@ static void version(void)
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
-static const struct command *find_command(const char *name)
|
|
+static const struct command *find_command(struct state *state, const char *name)
|
|
{
|
|
const struct command **p;
|
|
|
|
for (p = __start___command; p < __stop___command; p++) {
|
|
const struct command *cmd = *p;
|
|
|
|
+ if (state->vid >= 0 && cmd->type != SUBCOMMAND_VID)
|
|
+ continue;
|
|
+
|
|
+ if (state->vid < 0 && cmd->type == SUBCOMMAND_VID)
|
|
+ continue;
|
|
+
|
|
if (strcmp(cmd->name, name) == 0)
|
|
return cmd;
|
|
|
|
@@ -110,6 +143,51 @@ static const struct command *find_command(const char *name)
|
|
return NULL;
|
|
}
|
|
|
|
+static int parse_dev_args(struct state *state, int argc, char *argv[])
|
|
+{
|
|
+ unsigned long vid;
|
|
+ char *endptr;
|
|
+
|
|
+ /* not enough arguments to parse */
|
|
+ if (argc < 2) {
|
|
+ translate_mesh_iface(state);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (strcmp(argv[0], "vid") == 0) {
|
|
+ if (argv[1] == '\0') {
|
|
+ fprintf(stderr, "Error - unparsable vid\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ vid = strtoul(argv[1], &endptr, 0);
|
|
+ if (!endptr || *endptr != '\0') {
|
|
+ fprintf(stderr, "Error - unparsable vid\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (vid > 4095) {
|
|
+ fprintf(stderr, "Error - too large vid (max 4095)\n");
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ /* get mesh interface and overwrite vid afterwards */
|
|
+ translate_mesh_iface(state);
|
|
+ state->vid = vid;
|
|
+
|
|
+ return 2;
|
|
+ } else if (strcmp(argv[0], "vlan") == 0) {
|
|
+ state->arg_iface = argv[1];
|
|
+ translate_mesh_iface(state);
|
|
+
|
|
+ return 2;
|
|
+ } else {
|
|
+ /* parse vlan as part of -m parameter */
|
|
+ translate_mesh_iface(state);
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
int main(int argc, char **argv)
|
|
{
|
|
const struct command *cmd;
|
|
@@ -117,6 +195,7 @@ int main(int argc, char **argv)
|
|
.arg_iface = mesh_dfl_iface,
|
|
.cmd = NULL,
|
|
};
|
|
+ int dev_arguments;
|
|
int opt;
|
|
int ret;
|
|
|
|
@@ -152,7 +231,15 @@ int main(int argc, char **argv)
|
|
argc -= optind;
|
|
optind = 0;
|
|
|
|
- cmd = find_command(argv[0]);
|
|
+ /* parse arguments to identify vlan, ... */
|
|
+ dev_arguments = parse_dev_args(&state, argc, argv);
|
|
+ if (dev_arguments < 0)
|
|
+ goto err;
|
|
+
|
|
+ argv += dev_arguments;
|
|
+ argc -= dev_arguments;
|
|
+
|
|
+ cmd = find_command(&state, argv[0]);
|
|
if (!cmd) {
|
|
fprintf(stderr,
|
|
"Error - no valid command or debug table specified: %s\n",
|
|
@@ -162,8 +249,6 @@ int main(int argc, char **argv)
|
|
|
|
state.cmd = cmd;
|
|
|
|
- translate_mesh_iface(&state);
|
|
-
|
|
if (cmd->flags & COMMAND_FLAG_MESH_IFACE &&
|
|
check_mesh_iface(&state) < 0) {
|
|
fprintf(stderr,
|
|
diff --git a/main.h b/main.h
|
|
index 1a4701513c49ad8974b9c9189619f5dde622acd4..1d952610aefb8367bd52e24bea8c04c3d70b94ea 100644
|
|
--- a/main.h
|
|
+++ b/main.h
|
|
@@ -58,6 +58,7 @@ enum command_flags {
|
|
|
|
enum command_type {
|
|
SUBCOMMAND,
|
|
+ SUBCOMMAND_VID,
|
|
DEBUGTABLE,
|
|
};
|
|
|
|
@@ -84,7 +85,7 @@ struct command {
|
|
};
|
|
|
|
#define COMMAND_NAMED(_type, _name, _abbr, _handler, _flags, _arg, _usage) \
|
|
- static const struct command command_ ## _name = { \
|
|
+ static const struct command command_ ## _name ## _ ## _type = { \
|
|
.type = (_type), \
|
|
.name = (#_name), \
|
|
.abbr = _abbr, \
|
|
@@ -93,8 +94,8 @@ struct command {
|
|
.arg = (_arg), \
|
|
.usage = (_usage), \
|
|
}; \
|
|
- static const struct command *__command_ ## _name \
|
|
- __attribute__((__used__)) __attribute__ ((__section__ ("__command"))) = &command_ ## _name
|
|
+ static const struct command *__command_ ## _name ## _ ## _type \
|
|
+ __attribute__((__used__)) __attribute__ ((__section__ ("__command"))) = &command_ ## _name ## _ ## _type
|
|
|
|
#define COMMAND(_type, _handler, _abbr, _flags, _arg, _usage) \
|
|
COMMAND_NAMED(_type, _handler, _abbr, _handler, _flags, _arg, _usage)
|
|
diff --git a/man/batctl.8 b/man/batctl.8
|
|
index 0b430313075b5a7a4c796eba0867954e10061002..acb4288c4e6f59b322d20631ef8e3aee6f2215e5 100644
|
|
--- a/man/batctl.8
|
|
+++ b/man/batctl.8
|
|
@@ -68,7 +68,7 @@ free all attached interfaces and remove batman-adv interface.
|
|
If no parameter is given the current originator interval setting is displayed otherwise the parameter is used to set the
|
|
originator interval. The interval is in units of milliseconds.
|
|
.br
|
|
-.IP "\fBap_isolation\fP|\fBap\fP [\fB0\fP|\fB1\fP]"
|
|
+.IP "[\fBvlan <vdev>\fP|\fBvid <vid>\fP] \fBap_isolation\fP|\fBap\fP [\fB0\fP|\fB1\fP]"
|
|
If no parameter is given the current ap isolation setting is displayed. Otherwise the parameter is used to enable or
|
|
disable ap isolation. This command can be used in conjunction with "\-m" option to target per VLAN configurations.
|
|
.br
|
|
diff --git a/sys.c b/sys.c
|
|
index 39123db87d391b8898b7454eba7708515bfb3c78..f19719cfad61f36f2a5c1078305de83eb5be142a 100644
|
|
--- a/sys.c
|
|
+++ b/sys.c
|
|
@@ -141,9 +141,35 @@ int sys_simple_print_boolean(struct nl_msg *msg, void *arg,
|
|
|
|
static void settings_usage(struct state *state)
|
|
{
|
|
- fprintf(stderr, "Usage: batctl [options] %s|%s [parameters] %s\n",
|
|
- state->cmd->name, state->cmd->abbr,
|
|
- state->cmd->usage ? state->cmd->usage : "");
|
|
+ const char *default_prefixes[] = {
|
|
+ "",
|
|
+ NULL,
|
|
+ };
|
|
+ const char *vlan_prefixes[] = {
|
|
+ "vlan <vdev> ",
|
|
+ "vid <vid> ",
|
|
+ NULL,
|
|
+ };
|
|
+ const char *linestart = "Usage:";
|
|
+ const char **prefixes;
|
|
+ const char **prefix;
|
|
+
|
|
+ switch (state->cmd->type) {
|
|
+ case SUBCOMMAND_VID:
|
|
+ prefixes = vlan_prefixes;
|
|
+ break;
|
|
+ default:
|
|
+ prefixes = default_prefixes;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ for (prefix = &prefixes[0]; *prefix; prefix++) {
|
|
+ fprintf(stderr, "%s batctl [options] %s%s|%s [parameters] %s\n",
|
|
+ linestart, *prefix, state->cmd->name, state->cmd->abbr,
|
|
+ state->cmd->usage ? state->cmd->usage : "");
|
|
+
|
|
+ linestart = " ";
|
|
+ }
|
|
|
|
fprintf(stderr, "parameters:\n");
|
|
fprintf(stderr, " \t -h print this help\n");
|