lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210418120137.2605522-6-razor@blackwall.org>
Date:   Sun, 18 Apr 2021 15:01:36 +0300
From:   Nikolay Aleksandrov <razor@...ckwall.org>
To:     netdev@...r.kernel.org
Cc:     roopa@...dia.com, dsahern@...il.com,
        Nikolay Aleksandrov <nikolay@...dia.com>
Subject: [PATCH iproute2-next 5/6] bridge: vlan: add support for the new rtm dump call

From: Nikolay Aleksandrov <nikolay@...dia.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@...dia.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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ