bridge: vlan: add support for the new rtm dump call

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>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
Nikolay Aleksandrov 2021-04-18 15:01:36 +03:00 committed by David Ahern
parent 34c14bea22
commit e5f87c8341
4 changed files with 152 additions and 8 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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