bridge: vlan: add option set command and state option

Add a new per-vlan option set command. It allows to manipulate vlan
options, those can be bridge-wide or per-port depending on what device
is specified. The first option that can be set is the vlan STP state,
it is identical to the bridge port STP state. The man page is also
updated accordingly.

Example:
 $ bridge vlan set vid 10 dev br0 state learning
or a range:
 $ bridge vlan set vid 10-20 dev swp1 state blocking

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
Nikolay Aleksandrov 2021-04-18 15:01:34 +03:00 committed by David Ahern
parent f2f52fcabe
commit 04e2783d5e
2 changed files with 161 additions and 0 deletions

View File

@ -33,6 +33,7 @@ static void usage(void)
"Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n"
" [ pvid ] [ untagged ]\n"
" [ self ] [ master ]\n"
" bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
" bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
" bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n");
exit(-1);
@ -241,6 +242,100 @@ static int vlan_modify(int cmd, int argc, char **argv)
return 0;
}
static int vlan_option_set(int argc, char **argv)
{
struct {
struct nlmsghdr n;
struct br_vlan_msg bvm;
char buf[1024];
} req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
.n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_NEWVLAN,
.bvm.family = PF_BRIDGE,
};
struct bridge_vlan_info vinfo = {};
struct rtattr *afspec;
short vid_end = -1;
char *d = NULL;
short vid = -1;
int state = -1;
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
d = *argv;
} else if (strcmp(*argv, "vid") == 0) {
char *p;
NEXT_ARG();
p = strchr(*argv, '-');
if (p) {
*p = '\0';
p++;
vid = atoi(*argv);
vid_end = atoi(p);
if (vid >= vid_end || vid_end >= 4096) {
fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
vid, vid_end);
return -1;
}
} else {
vid = atoi(*argv);
}
} else if (strcmp(*argv, "state") == 0) {
char *endptr;
NEXT_ARG();
state = strtol(*argv, &endptr, 10);
if (!(**argv != '\0' && *endptr == '\0'))
state = parse_stp_state(*argv);
if (state == -1) {
fprintf(stderr, "Error: invalid STP state\n");
return -1;
}
} else {
if (matches(*argv, "help") == 0)
NEXT_ARG();
}
argc--; argv++;
}
if (d == NULL || vid == -1) {
fprintf(stderr, "Device and VLAN ID are required arguments.\n");
return -1;
}
req.bvm.ifindex = ll_name_to_index(d);
if (req.bvm.ifindex == 0) {
fprintf(stderr, "Cannot find network device \"%s\"\n", d);
return -1;
}
if (vid >= 4096) {
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
return -1;
}
afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
afspec->rta_type |= NLA_F_NESTED;
vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
vinfo.vid = vid;
addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO, &vinfo,
sizeof(vinfo));
if (vid_end != -1)
addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_RANGE,
vid_end);
if (state >= 0)
addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE, state);
addattr_nest_end(&req.n, afspec);
if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -1;
return 0;
}
/* In order to use this function for both filtering and non-filtering cases
* we need to make it a tristate:
* return -1 - if filtering we've gone over so don't continue
@ -667,6 +762,8 @@ int do_vlan(int argc, char **argv)
if (matches(*argv, "tunnelshow") == 0) {
return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO);
}
if (matches(*argv, "set") == 0)
return vlan_option_set(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
} else {

View File

@ -138,6 +138,15 @@ bridge \- show / manipulate bridge addresses and devices
.BR pvid " ] [ " untagged " ] [ "
.BR self " ] [ " master " ] "
.ti -8
.BR "bridge vlan set"
.B dev
.I DEV
.B vid
.IR VID " [ "
.B state
.IR STP_STATE " ] "
.ti -8
.BR "bridge vlan" " [ " show " | " tunnelshow " ] [ "
.B dev
@ -813,6 +822,61 @@ The
.BR "pvid " and " untagged"
flags are ignored.
.SS bridge vlan set - change vlan filter entry's options
This command changes vlan filter entry's options.
.TP
.BI dev " NAME"
the interface with which this vlan is associated.
.TP
.BI vid " VID"
the VLAN ID that identifies the vlan.
.TP
.BI state " STP_STATE "
the operation state of the vlan. One may enter STP state name (case insensitive), or one of the
numbers below. Negative inputs are ignored, and unrecognized names return an
error. Note that the state is set only for the vlan of the specified device, e.g. if it is
a bridge port then the state will be set only for the vlan of the port.
.B 0
- vlan is in STP
.B DISABLED
state. Make this vlan completely inactive for STP. This is also called
BPDU filter and could be used to disable STP on an untrusted vlan.
.sp
.B 1
- vlan is in STP
.B LISTENING
state. Only valid if STP is enabled on the bridge. In this
state the vlan listens for STP BPDUs and drops all other traffic frames.
.sp
.B 2
- vlan is in STP
.B LEARNING
state. Only valid if STP is enabled on the bridge. In this
state the vlan will accept traffic only for the purpose of updating MAC
address tables.
.sp
.B 3
- vlan is in STP
.B FORWARDING
state. This is the default vlan state.
.sp
.B 4
- vlan is in STP
.B BLOCKING
state. Only valid if STP is enabled on the bridge. This state
is used during the STP election process. In this state, the vlan will only process
STP BPDUs.
.sp
.SS bridge vlan show - list vlan configuration.
This command displays the current VLAN filter table.