All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
@ 2016-06-20 10:13 Nikolay Aleksandrov
  2016-06-21 16:01 ` Stephen Hemminger
  2016-06-21 18:07 ` [PATCH iproute2 net-next v2] " Nikolay Aleksandrov
  0 siblings, 2 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-06-20 10:13 UTC (permalink / raw)
  To: netdev; +Cc: stephen, roopa, Nikolay Aleksandrov

This patch adds support for the -statistics (-s) argument to the bridge
vlan show command which will display the per-vlan statistics and the bridge
device each vlan belongs to. The show command filtering options are both
supported, also the man page is updated to explain the new option.
This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
only the bridge vlans. Later we can add support for using the per-device
dump and filter it in the kernel instead.

Example:
$ bridge -s vlan
port	vlan id	stats
br0	 1	 RX: 33724730 bytes 492075 packets TX: 67409922 bytes 984029 packets
	 100	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
	 200	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
	 300	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
	 301	 RX: 169562135 bytes 790877 packets TX: 169550926 bytes 790824 packets
br1	 1	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets

Note that it will print the per-vlan statistics for all vlans in a bridge
even if the vlan is only added to ports. Later when we add per-port
per-vlan statistics support, we'll be able to print the exact ports each
vlan belongs to, not only the bridge.

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
 bridge/vlan.c        | 103 ++++++++++++++++++++++++++++++++++++++++++++-------
 include/libnetlink.h |   8 ++++
 lib/libnetlink.c     |  20 ++++++++++
 man/man8/bridge.8    |   6 +++
 4 files changed, 123 insertions(+), 14 deletions(-)

diff --git a/bridge/vlan.c b/bridge/vlan.c
index 717025ae6eec..b94630c17021 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -17,7 +17,7 @@ static unsigned int filter_index, filter_vlan;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
+	fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n");
 	fprintf(stderr, "                                                     [ self ] [ master ]\n");
 	fprintf(stderr, "       bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n");
 	exit(-1);
@@ -236,6 +236,63 @@ static int print_vlan(const struct sockaddr_nl *who,
 	return 0;
 }
 
+static void print_one_vlan_stats(FILE *fp,
+				 const struct bridge_vlan_xstats *vstats,
+				 int ifindex)
+{
+	if (filter_vlan) {
+		if (filter_vlan != vstats->vid)
+			return;
+		fprintf(fp, "%s", ll_index_to_name(ifindex));
+	}
+	fprintf(fp, "\t %hu\t RX: %llu bytes %llu packets TX: %llu bytes %llu packets\n",
+		vstats->vid, vstats->rx_bytes, vstats->rx_packets,
+		vstats->tx_bytes, vstats->tx_packets);
+}
+
+static int print_vlan_stats(const struct sockaddr_nl *who,
+			    struct nlmsghdr *n,
+			    void *arg)
+{
+	struct rtattr *tb[IFLA_STATS_MAX+1], *brtb[LINK_XSTATS_TYPE_MAX+1];
+	struct if_stats_msg *ifsm = NLMSG_DATA(n);
+	struct rtattr *i, *list;
+	int len = n->nlmsg_len;
+	FILE *fp = arg;
+	int rem;
+
+	len -= NLMSG_LENGTH(sizeof(*ifsm));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (filter_index && filter_index != ifsm->ifindex)
+		return 0;
+
+	parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
+	if (!tb[IFLA_STATS_LINK_XSTATS])
+		return 0;
+
+	parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX,
+		     RTA_DATA(tb[IFLA_STATS_LINK_XSTATS]),
+		     RTA_PAYLOAD(tb[IFLA_STATS_LINK_XSTATS]));
+	if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
+		return 0;
+
+	list = brtb[LINK_XSTATS_TYPE_BRIDGE];
+	rem = RTA_PAYLOAD(list);
+	if (!filter_vlan)
+		fprintf(fp, "%s", ll_index_to_name(ifsm->ifindex));
+	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		if (i->rta_type != BRIDGE_XSTATS_VLAN)
+			continue;
+		print_one_vlan_stats(fp, RTA_DATA(i), ifsm->ifindex);
+	}
+	fflush(fp);
+	return 0;
+}
+
 static int vlan_show(int argc, char **argv)
 {
 	char *filter_dev = NULL;
@@ -263,24 +320,41 @@ static int vlan_show(int argc, char **argv)
 		}
 	}
 
-	if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
-				    (compress_vlans ?
-				    RTEXT_FILTER_BRVLAN_COMPRESSED :
-				    RTEXT_FILTER_BRVLAN)) < 0) {
-		perror("Cannont send dump request");
-		exit(1);
-	}
+	if (!show_stats) {
+		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
+					    (compress_vlans ?
+					    RTEXT_FILTER_BRVLAN_COMPRESSED :
+					    RTEXT_FILTER_BRVLAN)) < 0) {
+			perror("Cannont send dump request");
+			exit(1);
+		}
 
-	printf("port\tvlan ids\n");
-	if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
-		fprintf(stderr, "Dump ternminated\n");
-		exit(1);
+		printf("port\tvlan ids\n");
+		if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
+	} else {
+		__u32 filt_mask;
+
+		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
+		if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
+						   RTM_GETSTATS,
+						   filt_mask) < 0) {
+			perror("Cannont send dump request");
+			exit(1);
+		}
+
+		printf("port\tvlan id\tstats\n");
+		if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
 	}
 
 	return 0;
 }
 
-
 int do_vlan(int argc, char **argv)
 {
 	ll_init_map(&rth);
@@ -296,8 +370,9 @@ int do_vlan(int argc, char **argv)
 			return vlan_show(argc-1, argv+1);
 		if (matches(*argv, "help") == 0)
 			usage();
-	} else
+	} else {
 		return vlan_show(0, NULL);
+	}
 
 	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
 	exit(-1);
diff --git a/include/libnetlink.h b/include/libnetlink.h
index f7b85dccef36..483509ca9635 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -44,6 +44,9 @@ typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
 int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type,
 				req_filter_fn_t fn)
 	__attribute__((warn_unused_result));
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+				   __u32 filt_mask)
+	__attribute__((warn_unused_result));
 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
 			     int len)
 	__attribute__((warn_unused_result));
@@ -202,6 +205,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
 #define NETNS_PAYLOAD(n)	NLMSG_PAYLOAD(n, sizeof(struct rtgenmsg))
 #endif
 
+#ifndef IFLA_STATS_RTA
+#define IFLA_STATS_RTA(r) \
+	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))))
+#endif
+
 /* User defined nlmsg_type which is used mostly for logging netlink
  * messages from dump file */
 #define NLMSG_TSTAMP	15
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 0adcbf3f6e38..f78eea38cf4a 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -157,6 +157,26 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
 	return send(rth->fd, (void*)&req, sizeof(req), 0);
 }
 
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+				   __u32 filt_mask)
+{
+	struct {
+		struct nlmsghdr nlh;
+		struct if_stats_msg ifsm;
+	} req;
+
+	memset(&req, 0, sizeof(req));
+	req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
+	req.nlh.nlmsg_type = type;
+	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+	req.ifsm.family = fam;
+	req.ifsm.filter_mask = filt_mask;
+
+	return send(rth->fd, (void *)&req, sizeof(req), 0);
+}
+
 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
 {
 	return send(rth->fd, buf, len, 0);
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 08e8a5bf5a08..dd7905db97e9 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -565,6 +565,12 @@ flags are ignored.
 
 This command displays the current VLAN filter table.
 
+.PP
+With the
+.B -statistics
+option, the command displays per-vlan traffic statistics and the bridge device
+each vlan belongs to.
+
 .SH bridge monitor - state monitoring
 
 The
-- 
2.1.4

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

* Re: [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
  2016-06-20 10:13 [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics Nikolay Aleksandrov
@ 2016-06-21 16:01 ` Stephen Hemminger
  2016-06-21 16:10   ` Nikolay Aleksandrov
  2016-06-21 18:07 ` [PATCH iproute2 net-next v2] " Nikolay Aleksandrov
  1 sibling, 1 reply; 8+ messages in thread
From: Stephen Hemminger @ 2016-06-21 16:01 UTC (permalink / raw)
  To: Nikolay Aleksandrov; +Cc: netdev, roopa

On Mon, 20 Jun 2016 12:13:19 +0200
Nikolay Aleksandrov <nikolay@cumulusnetworks.com> wrote:

> This patch adds support for the -statistics (-s) argument to the bridge
> vlan show command which will display the per-vlan statistics and the bridge
> device each vlan belongs to. The show command filtering options are both
> supported, also the man page is updated to explain the new option.
> This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
> only the bridge vlans. Later we can add support for using the per-device
> dump and filter it in the kernel instead.
> 
> Example:
> $ bridge -s vlan
> port	vlan id	stats
> br0	 1	 RX: 33724730 bytes 492075 packets TX: 67409922 bytes 984029 packets
> 	 100	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
> 	 200	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
> 	 300	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
> 	 301	 RX: 169562135 bytes 790877 packets TX: 169550926 bytes 790824 packets
> br1	 1	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
> 
> Note that it will print the per-vlan statistics for all vlans in a bridge
> even if the vlan is only added to ports. Later when we add per-port
> per-vlan statistics support, we'll be able to print the exact ports each
> vlan belongs to, not only the bridge.
> 
> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>

Thanks, this is a useful tool, but I think the formatting of output may need to be
reworked.  The bridge tool works similar to ip command. And in the ip command the
-s flag causes additional lines, but does not change the output format.

There is also double line spacing in current output, which scrolls off when
managing in little VM windows. Plush the port name is too narrow a field width

Why not something like:

$ bridge vlan
port	   vlan ids
virbr1	   1 PVID Egress Untagged
virbr4	   1 PVID Egress Untagged
virbr0	   1 PVID Egress Untagged

$ bridge -s vlan
virbr1	   1 PVID Egress Untagged
             RX: 33724730 bytes 492075 packets
             TX: 67409922 bytes 984029 packets
virbr0	   1 PVID Egress Untagged
             RX: 169562135 bytes 790877 packets 
             TX: 169550926 bytes 790824 packets

The -d detail flag would also be useful to implement

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

* Re: [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
  2016-06-21 16:01 ` Stephen Hemminger
@ 2016-06-21 16:10   ` Nikolay Aleksandrov
  2016-06-21 16:11     ` Nikolay Aleksandrov
  0 siblings, 1 reply; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-06-21 16:10 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, roopa

On 21/06/16 18:01, Stephen Hemminger wrote:
> On Mon, 20 Jun 2016 12:13:19 +0200
> Nikolay Aleksandrov <nikolay@cumulusnetworks.com> wrote:
> 
>> This patch adds support for the -statistics (-s) argument to the bridge
>> vlan show command which will display the per-vlan statistics and the bridge
>> device each vlan belongs to. The show command filtering options are both
>> supported, also the man page is updated to explain the new option.
>> This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
>> only the bridge vlans. Later we can add support for using the per-device
>> dump and filter it in the kernel instead.
>>
>> Example:
>> $ bridge -s vlan
>> port	vlan id	stats
>> br0	 1	 RX: 33724730 bytes 492075 packets TX: 67409922 bytes 984029 packets
>> 	 100	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>> 	 200	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>> 	 300	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>> 	 301	 RX: 169562135 bytes 790877 packets TX: 169550926 bytes 790824 packets
>> br1	 1	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>>
>> Note that it will print the per-vlan statistics for all vlans in a bridge
>> even if the vlan is only added to ports. Later when we add per-port
>> per-vlan statistics support, we'll be able to print the exact ports each
>> vlan belongs to, not only the bridge.
>>
>> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> 
> Thanks, this is a useful tool, but I think the formatting of output may need to be
> reworked.  The bridge tool works similar to ip command. And in the ip command the
> -s flag causes additional lines, but does not change the output format.

Indeed, I agree that it needs refinement.

> 
> There is also double line spacing in current output, which scrolls off when
> managing in little VM windows. Plush the port name is too narrow a field width

The port name width is the same as vlan show - 1 tab and a space.

> 
> Why not something like:
> 
> $ bridge vlan
> port	   vlan ids
> virbr1	   1 PVID Egress Untagged
> virbr4	   1 PVID Egress Untagged
> virbr0	   1 PVID Egress Untagged
> 
> $ bridge -s vlan
> virbr1	   1 PVID Egress Untagged
>              RX: 33724730 bytes 492075 packets
>              TX: 67409922 bytes 984029 packets
> virbr0	   1 PVID Egress Untagged
>              RX: 169562135 bytes 790877 packets 
>              TX: 169550926 bytes 790824 packets
> 
> The -d detail flag would also be useful to implement
> 

Yep, this was one of the formats I tested. The only thing that we currently
cannot implement is the flags printing as they're not exported via the stats
utility and really can't be because some of these entries may not exist on
the bridge device itself and it will get too confusing.
I left a few padding fields and I can export the flags if the entry exists
on the bridge device, then some will have the flags while others
will not, but it still sounds confusing to me. I'd prefer to just leave the
flags to the normal vlan show. What do you think ?

With your example:
 $ bridge -s vlan
 virbr1	   	1 
              RX: 33724730 bytes 492075 packets
              TX: 67409922 bytes 984029 packets

This way we can later add more fields like broadcast packets or multicast if
we ever start counting them.

I'll later add the "-brief" flag and print them on one line since with
thousands of vlans it comes in handy.

Cheers,
 Nik

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

* Re: [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
  2016-06-21 16:10   ` Nikolay Aleksandrov
@ 2016-06-21 16:11     ` Nikolay Aleksandrov
  2016-07-01  0:06       ` Stephen Hemminger
  0 siblings, 1 reply; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-06-21 16:11 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, roopa

On 21/06/16 18:10, Nikolay Aleksandrov wrote:
> On 21/06/16 18:01, Stephen Hemminger wrote:
>> On Mon, 20 Jun 2016 12:13:19 +0200
>> Nikolay Aleksandrov <nikolay@cumulusnetworks.com> wrote:
>>
>>> This patch adds support for the -statistics (-s) argument to the bridge
>>> vlan show command which will display the per-vlan statistics and the bridge
>>> device each vlan belongs to. The show command filtering options are both
>>> supported, also the man page is updated to explain the new option.
>>> This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
>>> only the bridge vlans. Later we can add support for using the per-device
>>> dump and filter it in the kernel instead.
>>>
>>> Example:
>>> $ bridge -s vlan
>>> port	vlan id	stats
>>> br0	 1	 RX: 33724730 bytes 492075 packets TX: 67409922 bytes 984029 packets
>>> 	 100	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>>> 	 200	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>>> 	 300	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>>> 	 301	 RX: 169562135 bytes 790877 packets TX: 169550926 bytes 790824 packets
>>> br1	 1	 RX: 0 bytes 0 packets TX: 0 bytes 0 packets
>>>
>>> Note that it will print the per-vlan statistics for all vlans in a bridge
>>> even if the vlan is only added to ports. Later when we add per-port
>>> per-vlan statistics support, we'll be able to print the exact ports each
>>> vlan belongs to, not only the bridge.
>>>
>>> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
>>
>> Thanks, this is a useful tool, but I think the formatting of output may need to be
>> reworked.  The bridge tool works similar to ip command. And in the ip command the
>> -s flag causes additional lines, but does not change the output format.
> 
> Indeed, I agree that it needs refinement.
> 

Or alternatively I can make it:
$ bridge vlan stats
a subcommand instead of using the "-s" argument in order to be consistent.
So it can have its own format.

>>
>> There is also double line spacing in current output, which scrolls off when
>> managing in little VM windows. Plush the port name is too narrow a field width
> 
> The port name width is the same as vlan show - 1 tab and a space.
> 
>>
>> Why not something like:
>>
>> $ bridge vlan
>> port	   vlan ids
>> virbr1	   1 PVID Egress Untagged
>> virbr4	   1 PVID Egress Untagged
>> virbr0	   1 PVID Egress Untagged
>>
>> $ bridge -s vlan
>> virbr1	   1 PVID Egress Untagged
>>              RX: 33724730 bytes 492075 packets
>>              TX: 67409922 bytes 984029 packets
>> virbr0	   1 PVID Egress Untagged
>>              RX: 169562135 bytes 790877 packets 
>>              TX: 169550926 bytes 790824 packets
>>
>> The -d detail flag would also be useful to implement
>>
> 
> Yep, this was one of the formats I tested. The only thing that we currently
> cannot implement is the flags printing as they're not exported via the stats
> utility and really can't be because some of these entries may not exist on
> the bridge device itself and it will get too confusing.
> I left a few padding fields and I can export the flags if the entry exists
> on the bridge device, then some will have the flags while others
> will not, but it still sounds confusing to me. I'd prefer to just leave the
> flags to the normal vlan show. What do you think ?
> 
> With your example:
>  $ bridge -s vlan
>  virbr1	   	1 
>               RX: 33724730 bytes 492075 packets
>               TX: 67409922 bytes 984029 packets
> 
> This way we can later add more fields like broadcast packets or multicast if
> we ever start counting them.
> 
> I'll later add the "-brief" flag and print them on one line since with
> thousands of vlans it comes in handy.
> 
> Cheers,
>  Nik
> 

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

* [PATCH iproute2 net-next v2] bridge: vlan: add support to display per-vlan statistics
  2016-06-20 10:13 [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics Nikolay Aleksandrov
  2016-06-21 16:01 ` Stephen Hemminger
@ 2016-06-21 18:07 ` Nikolay Aleksandrov
  2016-06-21 18:08   ` Nikolay Aleksandrov
  1 sibling, 1 reply; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-06-21 18:07 UTC (permalink / raw)
  To: netdev; +Cc: stephen, roopa, Nikolay Aleksandrov

This patch adds support for the stats argument to the bridge
vlan command which will display the per-vlan statistics and the bridge
device each vlan belongs to. The supported command filtering options are
dev and vid. Also the man page is updated to explain the new option.
This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
only the bridge vlans. Later we can add support for using the per-device
dump and filter it in the kernel instead.

Example:
$ bridge vlan stats
port             vlan id
br0               1
                    RX: 34816114 bytes 495195 packets
                    TX: 68501306 bytes 987149 packets
                  100
                    RX: 0 bytes 0 packets
                    TX: 0 bytes 0 packets
                  200
                    RX: 0 bytes 0 packets
                    TX: 0 bytes 0 packets
                  300
                    RX: 0 bytes 0 packets
                    TX: 0 bytes 0 packets
                  301
                    RX: 169562135 bytes 790877 packets
                    TX: 169550926 bytes 790824 packets
br1               1
                    RX: 0 bytes 0 packets
                    TX: 0 bytes 0 packets

Note that it will print the per-vlan statistics for all vlans in a bridge
even if the vlan is only added to ports. Later when we add per-port
per-vlan statistics support, we'll be able to print the exact ports each
vlan belongs to, not only the bridge.

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
v2: Change the output format as per Stephen's comment and change the -s use
to a subcommand called stats in order to have a different format than show,
update the man page appropriately.

 bridge/vlan.c        | 117 +++++++++++++++++++++++++++++++++++++++++++--------
 include/libnetlink.h |   8 ++++
 lib/libnetlink.c     |  20 +++++++++
 man/man8/bridge.8    |  23 +++++++++-
 4 files changed, 150 insertions(+), 18 deletions(-)

diff --git a/bridge/vlan.c b/bridge/vlan.c
index 717025ae6eec..e251a5cae917 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -14,12 +14,14 @@
 #include "utils.h"
 
 static unsigned int filter_index, filter_vlan;
+static int last_ifidx = -1;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
+	fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n");
 	fprintf(stderr, "                                                     [ self ] [ master ]\n");
 	fprintf(stderr, "       bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n");
+	fprintf(stderr, "       bridge vlan { stats } [ dev DEV ] [ vid VLAN_ID ]\n");
 	exit(-1);
 }
 
@@ -236,7 +238,67 @@ static int print_vlan(const struct sockaddr_nl *who,
 	return 0;
 }
 
-static int vlan_show(int argc, char **argv)
+static void print_one_vlan_stats(FILE *fp,
+				 const struct bridge_vlan_xstats *vstats,
+				 int ifindex)
+{
+	const char *ifname = "";
+
+	if (filter_vlan && filter_vlan != vstats->vid)
+		return;
+	if (last_ifidx != ifindex) {
+		ifname = ll_index_to_name(ifindex);
+		last_ifidx = ifindex;
+	}
+	fprintf(fp, "%-16s  %hu\n", ifname, vstats->vid);
+	fprintf(fp, "%-16s    RX: %llu bytes %llu packets\n",
+		"", vstats->rx_bytes, vstats->rx_packets);
+	fprintf(fp, "%-16s    TX: %llu bytes %llu packets\n",
+		"", vstats->tx_bytes, vstats->tx_packets);
+}
+
+static int print_vlan_stats(const struct sockaddr_nl *who,
+			    struct nlmsghdr *n,
+			    void *arg)
+{
+	struct rtattr *tb[IFLA_STATS_MAX+1], *brtb[LINK_XSTATS_TYPE_MAX+1];
+	struct if_stats_msg *ifsm = NLMSG_DATA(n);
+	struct rtattr *i, *list;
+	int len = n->nlmsg_len;
+	FILE *fp = arg;
+	int rem;
+
+	len -= NLMSG_LENGTH(sizeof(*ifsm));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (filter_index && filter_index != ifsm->ifindex)
+		return 0;
+
+	parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
+	if (!tb[IFLA_STATS_LINK_XSTATS])
+		return 0;
+
+	parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX,
+		     RTA_DATA(tb[IFLA_STATS_LINK_XSTATS]),
+		     RTA_PAYLOAD(tb[IFLA_STATS_LINK_XSTATS]));
+	if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
+		return 0;
+
+	list = brtb[LINK_XSTATS_TYPE_BRIDGE];
+	rem = RTA_PAYLOAD(list);
+	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		if (i->rta_type != BRIDGE_XSTATS_VLAN)
+			continue;
+		print_one_vlan_stats(fp, RTA_DATA(i), ifsm->ifindex);
+	}
+	fflush(fp);
+	return 0;
+}
+
+static int vlan_show(int argc, char **argv, bool do_show_stats)
 {
 	char *filter_dev = NULL;
 
@@ -263,24 +325,41 @@ static int vlan_show(int argc, char **argv)
 		}
 	}
 
-	if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
-				    (compress_vlans ?
-				    RTEXT_FILTER_BRVLAN_COMPRESSED :
-				    RTEXT_FILTER_BRVLAN)) < 0) {
-		perror("Cannont send dump request");
-		exit(1);
-	}
+	if (!do_show_stats) {
+		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
+					    (compress_vlans ?
+					    RTEXT_FILTER_BRVLAN_COMPRESSED :
+					    RTEXT_FILTER_BRVLAN)) < 0) {
+			perror("Cannont send dump request");
+			exit(1);
+		}
 
-	printf("port\tvlan ids\n");
-	if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
-		fprintf(stderr, "Dump ternminated\n");
-		exit(1);
+		printf("port\tvlan ids\n");
+		if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
+	} else {
+		__u32 filt_mask;
+
+		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
+		if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
+						   RTM_GETSTATS,
+						   filt_mask) < 0) {
+			perror("Cannont send dump request");
+			exit(1);
+		}
+
+		printf("%-16s vlan id\n", "port");
+		if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
 	}
 
 	return 0;
 }
 
-
 int do_vlan(int argc, char **argv)
 {
 	ll_init_map(&rth);
@@ -293,11 +372,15 @@ int do_vlan(int argc, char **argv)
 		if (matches(*argv, "show") == 0 ||
 		    matches(*argv, "lst") == 0 ||
 		    matches(*argv, "list") == 0)
-			return vlan_show(argc-1, argv+1);
+			return vlan_show(argc-1, argv+1, false);
+		if (matches(*argv, "stats") == 0 ||
+		    matches(*argv, "statistics") == 0)
+			return vlan_show(argc-1, argv+1, true);
 		if (matches(*argv, "help") == 0)
 			usage();
-	} else
-		return vlan_show(0, NULL);
+	} else {
+		return vlan_show(0, NULL, false);
+	}
 
 	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
 	exit(-1);
diff --git a/include/libnetlink.h b/include/libnetlink.h
index f7b85dccef36..483509ca9635 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -44,6 +44,9 @@ typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
 int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type,
 				req_filter_fn_t fn)
 	__attribute__((warn_unused_result));
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+				   __u32 filt_mask)
+	__attribute__((warn_unused_result));
 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
 			     int len)
 	__attribute__((warn_unused_result));
@@ -202,6 +205,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
 #define NETNS_PAYLOAD(n)	NLMSG_PAYLOAD(n, sizeof(struct rtgenmsg))
 #endif
 
+#ifndef IFLA_STATS_RTA
+#define IFLA_STATS_RTA(r) \
+	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))))
+#endif
+
 /* User defined nlmsg_type which is used mostly for logging netlink
  * messages from dump file */
 #define NLMSG_TSTAMP	15
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 0adcbf3f6e38..f78eea38cf4a 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -157,6 +157,26 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
 	return send(rth->fd, (void*)&req, sizeof(req), 0);
 }
 
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+				   __u32 filt_mask)
+{
+	struct {
+		struct nlmsghdr nlh;
+		struct if_stats_msg ifsm;
+	} req;
+
+	memset(&req, 0, sizeof(req));
+	req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
+	req.nlh.nlmsg_type = type;
+	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+	req.ifsm.family = fam;
+	req.ifsm.filter_mask = filt_mask;
+
+	return send(rth->fd, (void *)&req, sizeof(req), 0);
+}
+
 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
 {
 	return send(rth->fd, buf, len, 0);
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 08e8a5bf5a08..33a9b3d774ad 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -102,6 +102,13 @@ bridge \- show / manipulate bridge addresses and devices
 .IR DEV " ]"
 
 .ti -8
+.BR "bridge vlan stats " [ "
+.B dev
+.IR DEV " ] ["
+.B vid
+.IR VID " ]"
+
+.ti -8
 .BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]"
 
 .SH OPTIONS
@@ -561,10 +568,24 @@ The
 .BR "pvid " and " untagged"
 flags are ignored.
 
-.SS bridge vlan show - list vlan configuration.
+.SS bridge vlan show - list vlan configuration
 
 This command displays the current VLAN filter table.
 
+.SS bridge vlan stats - list vlan statistics
+
+This command displays the current per-VLAN traffic statistics and the bridge device
+each vlan belongs to.
+
+.TP
+.BI dev " DEV"
+the interface only whose entries should be listed. Default is to list all
+bridge interfaces.
+
+.TP
+.BI vid " VID"
+the vlan with VLAN ID which should be listed. Default is to list all vlans.
+
 .SH bridge monitor - state monitoring
 
 The
-- 
2.1.4

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

* Re: [PATCH iproute2 net-next v2] bridge: vlan: add support to display per-vlan statistics
  2016-06-21 18:07 ` [PATCH iproute2 net-next v2] " Nikolay Aleksandrov
@ 2016-06-21 18:08   ` Nikolay Aleksandrov
  0 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-06-21 18:08 UTC (permalink / raw)
  To: netdev; +Cc: stephen, roopa

On 21/06/16 20:07, Nikolay Aleksandrov wrote:
> This patch adds support for the stats argument to the bridge
> vlan command which will display the per-vlan statistics and the bridge
> device each vlan belongs to. The supported command filtering options are
> dev and vid. Also the man page is updated to explain the new option.
> This patch uses the new RTM_GETSTATS interface with a filter_mask to dump
> only the bridge vlans. Later we can add support for using the per-device
> dump and filter it in the kernel instead.
> 
> Example:
> $ bridge vlan stats
> port             vlan id
> br0               1
>                     RX: 34816114 bytes 495195 packets
>                     TX: 68501306 bytes 987149 packets
>                   100
>                     RX: 0 bytes 0 packets
>                     TX: 0 bytes 0 packets
>                   200
>                     RX: 0 bytes 0 packets
>                     TX: 0 bytes 0 packets
>                   300
>                     RX: 0 bytes 0 packets
>                     TX: 0 bytes 0 packets
>                   301
>                     RX: 169562135 bytes 790877 packets
>                     TX: 169550926 bytes 790824 packets
> br1               1
>                     RX: 0 bytes 0 packets
>                     TX: 0 bytes 0 packets
> 
> Note that it will print the per-vlan statistics for all vlans in a bridge
> even if the vlan is only added to ports. Later when we add per-port
> per-vlan statistics support, we'll be able to print the exact ports each
> vlan belongs to, not only the bridge.
> 
> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> ---
> v2: Change the output format as per Stephen's comment and change the -s use
> to a subcommand called stats in order to have a different format than show,
> update the man page appropriately.
> 

I forgot to add - I also tested this in a small VM window and it fits
well. :-)

Cheers,
 Nik

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

* Re: [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
  2016-06-21 16:11     ` Nikolay Aleksandrov
@ 2016-07-01  0:06       ` Stephen Hemminger
  2016-07-01  9:24         ` Nikolay Aleksandrov
  0 siblings, 1 reply; 8+ messages in thread
From: Stephen Hemminger @ 2016-07-01  0:06 UTC (permalink / raw)
  To: Nikolay Aleksandrov; +Cc: netdev, roopa

On Tue, 21 Jun 2016 18:11:59 +0200
Nikolay Aleksandrov <nikolay@cumulusnetworks.com> wrote:

> >> Thanks, this is a useful tool, but I think the formatting of output may need to be
> >> reworked.  The bridge tool works similar to ip command. And in the ip command the
> >> -s flag causes additional lines, but does not change the output format.  
> > 
> > Indeed, I agree that it needs refinement.
> >   
> 
> Or alternatively I can make it:
> $ bridge vlan stats
> a subcommand instead of using the "-s" argument in order to be consistent.
> So it can have its own format.

Why not:

$ bridge -s vlan show

to be consistent with:

$ ip -s li show

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

* Re: [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics
  2016-07-01  0:06       ` Stephen Hemminger
@ 2016-07-01  9:24         ` Nikolay Aleksandrov
  0 siblings, 0 replies; 8+ messages in thread
From: Nikolay Aleksandrov @ 2016-07-01  9:24 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, roopa

On 01/07/16 02:06, Stephen Hemminger wrote:
> On Tue, 21 Jun 2016 18:11:59 +0200
> Nikolay Aleksandrov <nikolay@cumulusnetworks.com> wrote:
> 
>>>> Thanks, this is a useful tool, but I think the formatting of output may need to be
>>>> reworked.  The bridge tool works similar to ip command. And in the ip command the
>>>> -s flag causes additional lines, but does not change the output format.  
>>>
>>> Indeed, I agree that it needs refinement.
>>>   
>>
>> Or alternatively I can make it:
>> $ bridge vlan stats
>> a subcommand instead of using the "-s" argument in order to be consistent.
>> So it can have its own format.
> 
> Why not:
> 
> $ bridge -s vlan show
> 
> to be consistent with:
> 
> $ ip -s li show
> 

The problem is that currently it cannot be formated the same as "bridge vlan show"
because it cannot contain the flags since all vlan stats are fetched from the
bridge device even though some vlans might exist only on the ports (or have different
flags on the ports).
That might change soon though, if my IGMP stats patches are accepted we'll be able
to fetch the vlan stats per port as well and thus print the flags and make the
output consistent with "bridge vlan show". Thus my first version of this patch that
just printed the stats will work in that case, we'll just add the flags and port
output later. If you'd like to go down this road please let me know.

Me and Roopa have been discussing an alternative way to fetch the stats via a new
command, something like:
$ bridge stats { <igmp> | <vlan> } [ dev DEV ] [ vid VID ]
because of the IGMP/MLD stats which don't fit any of the other commands for a "-s"
flag.

What do you think ?

Cheers,
 Nik

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

end of thread, other threads:[~2016-07-01  9:52 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-20 10:13 [PATCH iproute2 net-next] bridge: vlan: add support to display per-vlan statistics Nikolay Aleksandrov
2016-06-21 16:01 ` Stephen Hemminger
2016-06-21 16:10   ` Nikolay Aleksandrov
2016-06-21 16:11     ` Nikolay Aleksandrov
2016-07-01  0:06       ` Stephen Hemminger
2016-07-01  9:24         ` Nikolay Aleksandrov
2016-06-21 18:07 ` [PATCH iproute2 net-next v2] " Nikolay Aleksandrov
2016-06-21 18:08   ` Nikolay Aleksandrov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.