netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support
@ 2021-04-18 12:01 Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 1/6] bridge: rename and export print_portstate Nikolay Aleksandrov
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Hi,
This set extends the bridge vlan code to use the new vlan RTM calls
which allow to dump detailed per-port, per-vlan information and also to
manipulate the per-vlan options. It also allows to monitor any vlan
changes (add/del/option change). The rtm vlan dumps have an extensible
format which allows us to add new options and attributes easily, and
also to request the kernel to filter on different vlan information when
dumping. The new kernel dump code tries to use compressed vlan format as
much as possible (it includes netlink attributes for vlan start and
end) to reduce the number of generated messages and netlink traffic.
The iproute2 support is activated by using the "-d" flag when showing
vlan information, that will cause it to use the new rtm dump call and
get all the detailed information, if "-s" is also specified it will dump
per-vlan statistics as well. Obviously in that case the vlans cannot be
compressed. To change per-vlan options (currently only STP state is
supported) a new vlan command is added - "set". It can be used to set
options of bridge or port vlans and vlan ranges can be used, all of the
new vlan option code uses extack to show more understandable errors.
The set adds the first supported per-vlan option - STP state.
Man pages and usage information are updated accordingly.

Example:
 $ bridge -d vlan show
 port              vlan-id
 ens13             1 PVID Egress Untagged
                     state forwarding
 bridge            1 PVID Egress Untagged
                     state forwarding

 $ bridge vlan set vid 1 dev ens13 state blocking
 $ bridge -d vlan show
 port              vlan-id
 ens13             1 PVID Egress Untagged
                     state blocking
 bridge            1 PVID Egress Untagged
                     state forwarding

We plan to add many more per-vlan options in the future.

Thanks,
 Nik

Nikolay Aleksandrov (6):
  bridge: rename and export print_portstate
  bridge: add parse_stp_state helper
  bridge: vlan: add option set command and state option
  libnetlink: add bridge vlan dump request helper
  bridge: vlan: add support for the new rtm dump call
  bridge: monitor: add support for vlan monitoring

 bridge/br_common.h   |   3 +
 bridge/link.c        |  32 ++++--
 bridge/mdb.c         |   2 +-
 bridge/monitor.c     |  19 +++-
 bridge/vlan.c        | 255 +++++++++++++++++++++++++++++++++++++++++--
 include/libnetlink.h |   7 ++
 lib/libnetlink.c     |  19 ++++
 man/man8/bridge.8    |  75 ++++++++++++-
 8 files changed, 390 insertions(+), 22 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 1/6] bridge: rename and export print_portstate
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 2/6] bridge: add parse_stp_state helper Nikolay Aleksandrov
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Rename print_portstate to print_stp_state in preparation for use by vlan
code as well (per-vlan state), and export it. To be in line with the new
naming rename also port_states to stp_states as they'll be used for
vlans, too.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
 bridge/br_common.h |  1 +
 bridge/link.c      | 14 +++++++-------
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index b5798da300e8..e3f46765ab89 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -10,6 +10,7 @@ void print_vlan_info(struct rtattr *tb, int ifindex);
 int print_linkinfo(struct nlmsghdr *n, void *arg);
 int print_mdb_mon(struct nlmsghdr *n, void *arg);
 int print_fdb(struct nlmsghdr *n, void *arg);
+void print_stp_state(__u8 state);
 
 int do_fdb(int argc, char **argv);
 int do_mdb(int argc, char **argv);
diff --git a/bridge/link.c b/bridge/link.c
index d88c469db78e..a8cfa1814986 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -19,7 +19,7 @@
 
 static unsigned int filter_index;
 
-static const char *port_states[] = {
+static const char *stp_states[] = {
 	[BR_STATE_DISABLED] = "disabled",
 	[BR_STATE_LISTENING] = "listening",
 	[BR_STATE_LEARNING] = "learning",
@@ -68,11 +68,11 @@ static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
 	close_json_array(PRINT_ANY, "> ");
 }
 
-static void print_portstate(__u8 state)
+void print_stp_state(__u8 state)
 {
 	if (state <= BR_STATE_BLOCKING)
 		print_string(PRINT_ANY, "state",
-			     "state %s ", port_states[state]);
+			     "state %s ", stp_states[state]);
 	else
 		print_uint(PRINT_ANY, "state",
 			     "state (%d) ", state);
@@ -96,7 +96,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
 		parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
 
 		if (prtb[IFLA_BRPORT_STATE])
-			print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+			print_stp_state(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
 
 		if (prtb[IFLA_BRPORT_PRIORITY])
 			print_uint(PRINT_ANY, "priority",
@@ -161,7 +161,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
 			print_on_off(PRINT_ANY, "isolated", "isolated %s ",
 				     rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED]));
 	} else
-		print_portstate(rta_getattr_u8(attr));
+		print_stp_state(rta_getattr_u8(attr));
 }
 
 
@@ -359,12 +359,12 @@ static int brlink_modify(int argc, char **argv)
 		} else if (strcmp(*argv, "state") == 0) {
 			NEXT_ARG();
 			char *endptr;
-			size_t nstates = ARRAY_SIZE(port_states);
+			size_t nstates = ARRAY_SIZE(stp_states);
 
 			state = strtol(*argv, &endptr, 10);
 			if (!(**argv != '\0' && *endptr == '\0')) {
 				for (state = 0; state < nstates; state++)
-					if (strcasecmp(port_states[state], *argv) == 0)
+					if (strcasecmp(stp_states[state], *argv) == 0)
 						break;
 				if (state == nstates) {
 					fprintf(stderr,
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 2/6] bridge: add parse_stp_state helper
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 1/6] bridge: rename and export print_portstate Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 3/6] bridge: vlan: add option set command and state option Nikolay Aleksandrov
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Add a helper which parses an STP state string to its numeric value.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
 bridge/br_common.h |  1 +
 bridge/link.c      | 22 +++++++++++++++++-----
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index e3f46765ab89..33e56452702b 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -11,6 +11,7 @@ int print_linkinfo(struct nlmsghdr *n, void *arg);
 int print_mdb_mon(struct nlmsghdr *n, void *arg);
 int print_fdb(struct nlmsghdr *n, void *arg);
 void print_stp_state(__u8 state);
+int parse_stp_state(const char *arg);
 
 int do_fdb(int argc, char **argv);
 int do_mdb(int argc, char **argv);
diff --git a/bridge/link.c b/bridge/link.c
index a8cfa1814986..205a2fe79c1a 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -78,6 +78,21 @@ void print_stp_state(__u8 state)
 			     "state (%d) ", state);
 }
 
+int parse_stp_state(const char *arg)
+{
+	size_t nstates = ARRAY_SIZE(stp_states);
+	int state;
+
+	for (state = 0; state < nstates; state++)
+		if (strcmp(stp_states[state], arg) == 0)
+			break;
+
+	if (state == nstates)
+		state = -1;
+
+	return state;
+}
+
 static void print_hwmode(__u16 mode)
 {
 	if (mode >= ARRAY_SIZE(hw_mode))
@@ -359,14 +374,11 @@ static int brlink_modify(int argc, char **argv)
 		} else if (strcmp(*argv, "state") == 0) {
 			NEXT_ARG();
 			char *endptr;
-			size_t nstates = ARRAY_SIZE(stp_states);
 
 			state = strtol(*argv, &endptr, 10);
 			if (!(**argv != '\0' && *endptr == '\0')) {
-				for (state = 0; state < nstates; state++)
-					if (strcasecmp(stp_states[state], *argv) == 0)
-						break;
-				if (state == nstates) {
+				state = parse_stp_state(*argv);
+				if (state == -1) {
 					fprintf(stderr,
 						"Error: invalid STP port state\n");
 					return -1;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 3/6] bridge: vlan: add option set command and state option
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 1/6] bridge: rename and export print_portstate Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 2/6] bridge: add parse_stp_state helper Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 4/6] libnetlink: add bridge vlan dump request helper Nikolay Aleksandrov
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

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>
---
 bridge/vlan.c     | 97 +++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/bridge.8 | 64 +++++++++++++++++++++++++++++++
 2 files changed, 161 insertions(+)

diff --git a/bridge/vlan.c b/bridge/vlan.c
index 0d142bc9055d..09884870df81 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -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 {
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 9d8663bd23cc..90dcae73ce71 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -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.
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 4/6] libnetlink: add bridge vlan dump request helper
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
                   ` (2 preceding siblings ...)
  2021-04-18 12:01 ` [PATCH iproute2-next 3/6] bridge: vlan: add option set command and state option Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 5/6] bridge: vlan: add support for the new rtm dump call Nikolay Aleksandrov
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Add rtnl bridge vlan dump request helper which will be used to retrieve
bridge vlan information and options.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
 include/libnetlink.h |  2 ++
 lib/libnetlink.c     | 19 +++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/include/libnetlink.h b/include/libnetlink.h
index e8ed5d7fb495..da96c69b9ede 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -69,6 +69,8 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
 int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
+int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
+	__attribute__((warn_unused_result));
 int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
 	__attribute__((warn_unused_result));
 
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 6885087b34f9..2f2cc1fe0a61 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -450,6 +450,25 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
 	return send(rth->fd, &req, sizeof(req), 0);
 }
 
+int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
+{
+	struct {
+		struct nlmsghdr nlh;
+		struct br_vlan_msg bvm;
+		char buf[256];
+	} req = {
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
+		.nlh.nlmsg_type = RTM_GETVLAN,
+		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
+		.bvm.family = family,
+	};
+
+	addattr32(&req.nlh, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS, dump_flags);
+
+	return send(rth->fd, &req, sizeof(req), 0);
+}
+
 int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
 {
 	struct {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 5/6] bridge: vlan: add support for the new rtm dump call
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
                   ` (3 preceding siblings ...)
  2021-04-18 12:01 ` [PATCH iproute2-next 4/6] libnetlink: add bridge vlan dump request helper Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-18 12:01 ` [PATCH iproute2-next 6/6] bridge: monitor: add support for vlan monitoring Nikolay Aleksandrov
  2021-04-22  5:21 ` [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support David Ahern
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Use the new bridge vlan rtm dump helper to dump all of the available
vlan information when -details (-d) is used with vlan show. It is also
capable of dumping vlan stats if -statistics (-s) is added.
Currently this is the only interface capable of dumping per-vlan
options. The vlan dump format is compatible with current vlan show, it
uses the same helpers to dump vlan information. The new addition is one
line which will contain the per-vlan options (similar to ip -d link show
for ports). Currently only the vlan STP state is printed.
The call uses compressed vlan format by default.

Example:
$ bridge -s -d vlan show
port              vlan-id
virbr1            1 PVID Egress Untagged
                    state forwarding

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
 bridge/br_common.h   |   1 +
 bridge/vlan.c        | 147 ++++++++++++++++++++++++++++++++++++++++---
 include/libnetlink.h |   5 ++
 man/man8/bridge.8    |   7 ++-
 4 files changed, 152 insertions(+), 8 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index 33e56452702b..43870546ff28 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -12,6 +12,7 @@ int print_mdb_mon(struct nlmsghdr *n, void *arg);
 int print_fdb(struct nlmsghdr *n, void *arg);
 void print_stp_state(__u8 state);
 int parse_stp_state(const char *arg);
+int print_vlan_rtm(struct nlmsghdr *n, void *arg);
 
 int do_fdb(int argc, char **argv);
 int do_mdb(int argc, char **argv);
diff --git a/bridge/vlan.c b/bridge/vlan.c
index 09884870df81..c681e14189b8 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -16,6 +16,7 @@
 #include "utils.h"
 
 static unsigned int filter_index, filter_vlan;
+static int vlan_rtm_cur_ifidx = -1;
 
 enum vlan_show_subject {
 	VLAN_SHOW_VLAN,
@@ -517,14 +518,8 @@ static void print_vlan_flags(__u16 flags)
 	close_json_array(PRINT_JSON, NULL);
 }
 
-static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
+static void __print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
 {
-	open_json_object(NULL);
-
-	print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
-	print_vlan_flags(vstats->flags);
-	print_nl();
-
 	print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s    ", "");
 	print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes",
 		     vstats->rx_bytes);
@@ -536,6 +531,16 @@ static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
 		     vstats->tx_bytes);
 	print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n",
 		     vstats->tx_packets);
+}
+
+static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
+{
+	open_json_object(NULL);
+
+	print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
+	print_vlan_flags(vstats->flags);
+	print_nl();
+	__print_one_vlan_stats(vstats);
 
 	close_json_object();
 }
@@ -616,6 +621,105 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg)
 	return 0;
 }
 
+int print_vlan_rtm(struct nlmsghdr *n, void *arg)
+{
+	struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
+	struct br_vlan_msg *bvm = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	bool newport = false;
+	int rem;
+
+	if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
+	    n->nlmsg_type != RTM_GETVLAN) {
+		fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(sizeof(*bvm));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (bvm->family != AF_BRIDGE)
+		return 0;
+
+	if (filter_index && filter_index != bvm->ifindex)
+		return 0;
+
+	if (vlan_rtm_cur_ifidx == -1 || vlan_rtm_cur_ifidx != bvm->ifindex) {
+		if (vlan_rtm_cur_ifidx != -1)
+			close_vlan_port();
+		open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN);
+		vlan_rtm_cur_ifidx = bvm->ifindex;
+		newport = true;
+	}
+
+	rem = len;
+	for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
+		struct bridge_vlan_xstats vstats;
+		struct bridge_vlan_info *vinfo;
+		__u32 vrange = 0;
+		__u8 state = 0;
+
+		parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
+				   RTA_PAYLOAD(a), NLA_F_NESTED);
+		vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
+
+		memset(&vstats, 0, sizeof(vstats));
+		if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
+			vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
+		else
+			vrange = vinfo->vid;
+
+		if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
+			state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
+
+		if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
+			struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
+			struct rtattr *attr;
+
+			attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
+			parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
+				     RTA_PAYLOAD(attr));
+
+			if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
+				attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
+				vstats.rx_bytes = rta_getattr_u64(attr);
+			}
+			if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
+				attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
+				vstats.rx_packets = rta_getattr_u64(attr);
+			}
+			if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
+				attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
+				vstats.tx_packets = rta_getattr_u64(attr);
+			}
+			if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
+				attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
+				vstats.tx_bytes = rta_getattr_u64(attr);
+			}
+		}
+		open_json_object(NULL);
+		if (!newport)
+			print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s  ", "");
+		else
+			newport = false;
+		print_range("vlan", vinfo->vid, vrange);
+		print_vlan_flags(vinfo->flags);
+		print_nl();
+		print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s    ", "");
+		print_stp_state(state);
+		print_nl();
+		if (show_stats)
+			__print_one_vlan_stats(&vstats);
+		close_json_object();
+	}
+
+	return 0;
+}
+
 static int vlan_show(int argc, char **argv, int subject)
 {
 	char *filter_dev = NULL;
@@ -644,6 +748,34 @@ static int vlan_show(int argc, char **argv, int subject)
 
 	new_json_obj(json);
 
+	/* if show_details is true then use the new bridge vlan dump format */
+	if (show_details && subject == VLAN_SHOW_VLAN) {
+		__u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0;
+
+		if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
+			perror("Cannot send dump request");
+			exit(1);
+		}
+
+		if (!is_json_context()) {
+			printf("%-" __stringify(IFNAMSIZ) "s  %-"
+			       __stringify(VLAN_ID_LEN) "s", "port",
+			       "vlan-id");
+			printf("\n");
+		}
+
+		ret = rtnl_dump_filter(&rth, print_vlan_rtm, &subject);
+		if (ret < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
+
+		if (vlan_rtm_cur_ifidx != -1)
+			close_vlan_port();
+
+		goto out;
+	}
+
 	if (!show_stats) {
 		if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
 					     (compress_vlans ?
@@ -697,6 +829,7 @@ static int vlan_show(int argc, char **argv, int subject)
 		}
 	}
 
+out:
 	delete_json_obj();
 	fflush(stdout);
 	return 0;
diff --git a/include/libnetlink.h b/include/libnetlink.h
index da96c69b9ede..6bff6bae6ddf 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -285,6 +285,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
 	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))))
 #endif
 
+#ifndef BRVLAN_RTA
+#define BRVLAN_RTA(r) \
+	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_vlan_msg))))
+#endif
+
 /* User defined nlmsg_type which is used mostly for logging netlink
  * messages from dump file */
 #define NLMSG_TSTAMP	15
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 90dcae73ce71..9c8ebac3c6aa 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -171,7 +171,7 @@ As a rule, the information is statistics or some time values.
 
 .TP
 .BR "\-d" , " \-details"
-print detailed information about MDB router ports.
+print detailed information about bridge vlan filter entries or MDB router ports.
 
 .TP
 .BR "\-n" , " \-net" , " \-netns " <NETNS>
@@ -881,6 +881,11 @@ STP BPDUs.
 
 This command displays the current VLAN filter table.
 
+.PP
+With the
+.B -details
+option, the command becomes verbose. It displays the per-vlan options.
+
 .PP
 With the
 .B -statistics
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH iproute2-next 6/6] bridge: monitor: add support for vlan monitoring
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
                   ` (4 preceding siblings ...)
  2021-04-18 12:01 ` [PATCH iproute2-next 5/6] bridge: vlan: add support for the new rtm dump call Nikolay Aleksandrov
@ 2021-04-18 12:01 ` Nikolay Aleksandrov
  2021-04-22  5:21 ` [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support David Ahern
  6 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2021-04-18 12:01 UTC (permalink / raw)
  To: netdev; +Cc: roopa, dsahern, Nikolay Aleksandrov

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Add support for vlan activity monitoring, we display vlan notifications on
vlan add/del/options change. The man page and help are also updated
accordingly.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
---
 bridge/br_common.h |  2 +-
 bridge/mdb.c       |  2 +-
 bridge/monitor.c   | 19 ++++++++++++++++++-
 bridge/vlan.c      | 15 +++++++++++++--
 man/man8/bridge.8  |  4 ++--
 5 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index 43870546ff28..b9adafd98dea 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -12,7 +12,7 @@ int print_mdb_mon(struct nlmsghdr *n, void *arg);
 int print_fdb(struct nlmsghdr *n, void *arg);
 void print_stp_state(__u8 state);
 int parse_stp_state(const char *arg);
-int print_vlan_rtm(struct nlmsghdr *n, void *arg);
+int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor);
 
 int do_fdb(int argc, char **argv);
 int do_mdb(int argc, char **argv);
diff --git a/bridge/mdb.c b/bridge/mdb.c
index ef89258bc5c3..b427d878677f 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -16,9 +16,9 @@
 #include <arpa/inet.h>
 
 #include "libnetlink.h"
+#include "utils.h"
 #include "br_common.h"
 #include "rt_names.h"
-#include "utils.h"
 #include "json_print.h"
 
 #ifndef MDBA_RTA
diff --git a/bridge/monitor.c b/bridge/monitor.c
index 08439a60288a..88f52f52f084 100644
--- a/bridge/monitor.c
+++ b/bridge/monitor.c
@@ -31,7 +31,7 @@ static int prefix_banner;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | all]\n");
+	fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | all]\n");
 	exit(-1);
 }
 
@@ -67,6 +67,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
 		print_nlmsg_timestamp(fp, n);
 		return 0;
 
+	case RTM_NEWVLAN:
+	case RTM_DELVLAN:
+		if (prefix_banner)
+			fprintf(fp, "[VLAN]");
+		return print_vlan_rtm(n, arg, true);
+
 	default:
 		return 0;
 	}
@@ -79,6 +85,7 @@ int do_monitor(int argc, char **argv)
 	int llink = 0;
 	int lneigh = 0;
 	int lmdb = 0;
+	int lvlan = 0;
 
 	rtnl_close(&rth);
 
@@ -95,8 +102,12 @@ int do_monitor(int argc, char **argv)
 		} else if (matches(*argv, "mdb") == 0) {
 			lmdb = 1;
 			groups = 0;
+		} else if (matches(*argv, "vlan") == 0) {
+			lvlan = 1;
+			groups = 0;
 		} else if (strcmp(*argv, "all") == 0) {
 			groups = ~RTMGRP_TC;
+			lvlan = 1;
 			prefix_banner = 1;
 		} else if (matches(*argv, "help") == 0) {
 			usage();
@@ -134,6 +145,12 @@ int do_monitor(int argc, char **argv)
 
 	if (rtnl_open(&rth, groups) < 0)
 		exit(1);
+
+	if (lvlan && rtnl_add_nl_group(&rth, RTNLGRP_BRVLAN) < 0) {
+		fprintf(stderr, "Failed to add bridge vlan group to list\n");
+		exit(1);
+	}
+
 	ll_init_map(&rth);
 
 	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
diff --git a/bridge/vlan.c b/bridge/vlan.c
index c681e14189b8..9bb9e28d11bb 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -621,7 +621,7 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg)
 	return 0;
 }
 
-int print_vlan_rtm(struct nlmsghdr *n, void *arg)
+int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
 {
 	struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
 	struct br_vlan_msg *bvm = NLMSG_DATA(n);
@@ -648,6 +648,12 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg)
 	if (filter_index && filter_index != bvm->ifindex)
 		return 0;
 
+	if (n->nlmsg_type == RTM_DELVLAN)
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+	if (monitor)
+		vlan_rtm_cur_ifidx = -1;
+
 	if (vlan_rtm_cur_ifidx == -1 || vlan_rtm_cur_ifidx != bvm->ifindex) {
 		if (vlan_rtm_cur_ifidx != -1)
 			close_vlan_port();
@@ -720,6 +726,11 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg)
 	return 0;
 }
 
+static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
+{
+	return print_vlan_rtm(n, arg, false);
+}
+
 static int vlan_show(int argc, char **argv, int subject)
 {
 	char *filter_dev = NULL;
@@ -764,7 +775,7 @@ static int vlan_show(int argc, char **argv, int subject)
 			printf("\n");
 		}
 
-		ret = rtnl_dump_filter(&rth, print_vlan_rtm, &subject);
+		ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject);
 		if (ret < 0) {
 			fprintf(stderr, "Dump terminated\n");
 			exit(1);
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 9c8ebac3c6aa..eec7df4383bc 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -153,7 +153,7 @@ bridge \- show / manipulate bridge addresses and devices
 .IR DEV " ]"
 
 .ti -8
-.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]"
+.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
 
 .SH OPTIONS
 
@@ -911,7 +911,7 @@ command is the first in the command line and then the object list follows:
 .I OBJECT-LIST
 is the list of object types that we want to monitor.
 It may contain
-.BR link ", " fdb ", and " mdb "."
+.BR link ", " fdb ", " vlan " and " mdb "."
 If no
 .B file
 argument is given,
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support
  2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
                   ` (5 preceding siblings ...)
  2021-04-18 12:01 ` [PATCH iproute2-next 6/6] bridge: monitor: add support for vlan monitoring Nikolay Aleksandrov
@ 2021-04-22  5:21 ` David Ahern
  6 siblings, 0 replies; 8+ messages in thread
From: David Ahern @ 2021-04-22  5:21 UTC (permalink / raw)
  To: Nikolay Aleksandrov, netdev; +Cc: roopa, Nikolay Aleksandrov

On 4/18/21 5:01 AM, Nikolay Aleksandrov wrote:
> From: Nikolay Aleksandrov <nikolay@nvidia.com>
> 
> Hi,
> This set extends the bridge vlan code to use the new vlan RTM calls
> which allow to dump detailed per-port, per-vlan information and also to
> manipulate the per-vlan options. It also allows to monitor any vlan
> changes (add/del/option change). The rtm vlan dumps have an extensible
> format which allows us to add new options and attributes easily, and
> also to request the kernel to filter on different vlan information when
> dumping. The new kernel dump code tries to use compressed vlan format as
> much as possible (it includes netlink attributes for vlan start and
> end) to reduce the number of generated messages and netlink traffic.
> The iproute2 support is activated by using the "-d" flag when showing
> vlan information, that will cause it to use the new rtm dump call and
> get all the detailed information, if "-s" is also specified it will dump
> per-vlan statistics as well. Obviously in that case the vlans cannot be
> compressed. To change per-vlan options (currently only STP state is
> supported) a new vlan command is added - "set". It can be used to set
> options of bridge or port vlans and vlan ranges can be used, all of the
> new vlan option code uses extack to show more understandable errors.
> The set adds the first supported per-vlan option - STP state.
> Man pages and usage information are updated accordingly.
> 
> Example:
>  $ bridge -d vlan show
>  port              vlan-id
>  ens13             1 PVID Egress Untagged
>                      state forwarding
>  bridge            1 PVID Egress Untagged
>                      state forwarding
> 
>  $ bridge vlan set vid 1 dev ens13 state blocking
>  $ bridge -d vlan show
>  port              vlan-id
>  ens13             1 PVID Egress Untagged
>                      state blocking
>  bridge            1 PVID Egress Untagged
>                      state forwarding
> 
> We plan to add many more per-vlan options in the future.
> 

applied. Thanks, Nik


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-04-22  5:21 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-18 12:01 [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 1/6] bridge: rename and export print_portstate Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 2/6] bridge: add parse_stp_state helper Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 3/6] bridge: vlan: add option set command and state option Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 4/6] libnetlink: add bridge vlan dump request helper Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 5/6] bridge: vlan: add support for the new rtm dump call Nikolay Aleksandrov
2021-04-18 12:01 ` [PATCH iproute2-next 6/6] bridge: monitor: add support for vlan monitoring Nikolay Aleksandrov
2021-04-22  5:21 ` [PATCH iproute2-next 0/6] bridge: vlan: add per-vlan options support David Ahern

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).