@@ -12,7 +12,8 @@ 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, bool monitor);
+int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor,
+ bool global_only);
int do_fdb(int argc, char **argv);
int do_mdb(int argc, char **argv);
@@ -71,7 +71,7 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
case RTM_DELVLAN:
if (prefix_banner)
fprintf(fp, "[VLAN]");
- return print_vlan_rtm(n, arg, true);
+ return print_vlan_rtm(n, arg, true, false);
default:
return 0;
@@ -36,7 +36,8 @@ static void usage(void)
" [ 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");
+ " bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n"
+ " bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
exit(-1);
}
@@ -621,11 +622,89 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg)
return 0;
}
-int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
+static void print_vlan_global_opts(struct rtattr *a)
+{
+ struct rtattr *vtb[BRIDGE_VLANDB_GOPTS_MAX + 1];
+ __u16 vid, vrange = 0;
+
+ if ((a->rta_type & NLA_TYPE_MASK) != BRIDGE_VLANDB_GLOBAL_OPTIONS)
+ return;
+
+ parse_rtattr_flags(vtb, BRIDGE_VLANDB_GOPTS_MAX, RTA_DATA(a),
+ RTA_PAYLOAD(a), NLA_F_NESTED);
+ vid = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_ID]);
+ if (vtb[BRIDGE_VLANDB_GOPTS_RANGE])
+ vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_RANGE]);
+ else
+ vrange = vid;
+ print_range("vlan", vid, vrange);
+ print_nl();
+}
+
+static void print_vlan_opts(struct rtattr *a)
+{
+ struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1];
+ struct bridge_vlan_xstats vstats;
+ struct bridge_vlan_info *vinfo;
+ __u16 vrange = 0;
+ __u8 state = 0;
+
+ if ((a->rta_type & NLA_TYPE_MASK) != BRIDGE_VLANDB_ENTRY)
+ return;
+
+ 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);
+ }
+ }
+ 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);
+}
+
+int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor, bool global_only)
{
- struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
struct br_vlan_msg *bvm = NLMSG_DATA(n);
int len = n->nlmsg_len;
+ struct rtattr *a;
int rem;
if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
@@ -660,49 +739,13 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
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]);
+ unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
- 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));
+ /* skip unknown attributes */
+ if (rta_type > BRIDGE_VLANDB_MAX ||
+ (global_only && rta_type != BRIDGE_VLANDB_GLOBAL_OPTIONS))
+ continue;
- 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);
- }
- }
if (vlan_rtm_cur_ifidx != bvm->ifindex) {
open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN);
open_json_object(NULL);
@@ -711,14 +754,16 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
open_json_object(NULL);
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
}
- 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);
+
+ switch (rta_type) {
+ case BRIDGE_VLANDB_ENTRY:
+ print_vlan_opts(a);
+ break;
+ case BRIDGE_VLANDB_GLOBAL_OPTIONS:
+ print_vlan_global_opts(a);
+ break;
+ }
+
close_json_object();
}
@@ -727,7 +772,12 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
{
- return print_vlan_rtm(n, arg, false);
+ return print_vlan_rtm(n, arg, false, false);
+}
+
+static int print_vlan_rtm_global_filter(struct nlmsghdr *n, void *arg)
+{
+ return print_vlan_rtm(n, arg, false, true);
}
static int vlan_show(int argc, char **argv, int subject)
@@ -845,6 +895,61 @@ out:
return 0;
}
+static int vlan_global_show(int argc, char **argv)
+{
+ __u32 dump_flags = BRIDGE_VLANDB_DUMPF_GLOBAL;
+ int ret = 0, subject = VLAN_SHOW_VLAN;
+ char *filter_dev = NULL;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (filter_dev)
+ duparg("dev", *argv);
+ filter_dev = *argv;
+ } else if (strcmp(*argv, "vid") == 0) {
+ NEXT_ARG();
+ if (filter_vlan)
+ duparg("vid", *argv);
+ filter_vlan = atoi(*argv);
+ }
+ argc--; argv++;
+ }
+
+ if (filter_dev) {
+ filter_index = ll_name_to_index(filter_dev);
+ if (!filter_index)
+ return nodev(filter_dev);
+ }
+
+ new_json_obj(json);
+
+ 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_global_filter, &subject);
+ if (ret < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ if (vlan_rtm_cur_ifidx != -1)
+ close_vlan_port();
+
+ delete_json_obj();
+ fflush(stdout);
+ return 0;
+}
+
void print_vlan_info(struct rtattr *tb, int ifindex)
{
struct rtattr *i, *list = tb;
@@ -889,6 +994,22 @@ void print_vlan_info(struct rtattr *tb, int ifindex)
close_vlan_port();
}
+static int vlan_global(int argc, char **argv)
+{
+ if (argc > 0) {
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return vlan_global_show(argc-1, argv+1);
+ else
+ usage();
+ } else {
+ return vlan_global_show(0, NULL);
+ }
+
+ return 0;
+}
+
int do_vlan(int argc, char **argv)
{
ll_init_map(&rth);
@@ -907,6 +1028,8 @@ int do_vlan(int argc, char **argv)
}
if (matches(*argv, "set") == 0)
return vlan_option_set(argc-1, argv+1);
+ if (matches(*argv, "global") == 0)
+ return vlan_global(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
} else {
@@ -152,6 +152,13 @@ bridge \- show / manipulate bridge addresses and devices
.B dev
.IR DEV " ]"
+.ti -8
+.BR "bridge vlan global" " [ " show " ] [ "
+.B dev
+.IR DEV " ] [ "
+.B vid
+.IR VID " ]"
+
.ti -8
.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
@@ -895,6 +902,20 @@ option, the command displays per-vlan traffic statistics.
This command displays the current vlan tunnel info mapping.
+.SS bridge vlan global show - list global vlan options.
+
+This command displays the global VLAN options for each VLAN entry.
+
+.TP
+.BI dev " DEV"
+the interface only whose VLAN global options should be listed. Default is to list
+all bridge interfaces.
+
+.TP
+.BI vid " VID"
+the VLAN ID only whose global options should be listed. Default is to list
+all vlans.
+
.SH bridge monitor - state monitoring
The