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