From 720f8613bd161253fc115b8e93f02a2d5f98c04b Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Sat, 28 Aug 2021 14:07:50 +0300 Subject: [PATCH] bridge: vlan: add support to show global vlan options Add support for new bridge vlan command grouping called global which operates on global options. The first command it supports is "show". To do that we update print_vlan_rtm to recognize the global vlan options attribute and parse it properly. Man page and help are also updated with the new command. Syntax is: $ bridge vlan global show [ vid VID ] [ dev DEV ] Signed-off-by: Nikolay Aleksandrov Signed-off-by: David Ahern --- bridge/br_common.h | 3 +- bridge/monitor.c | 2 +- bridge/vlan.c | 110 +++++++++++++++++++++++++++++++++++++++++++-- man/man8/bridge.8 | 21 +++++++++ 4 files changed, 130 insertions(+), 6 deletions(-) diff --git a/bridge/br_common.h b/bridge/br_common.h index b9adafd9..09f42c81 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -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); diff --git a/bridge/monitor.c b/bridge/monitor.c index 88f52f52..845e221a 100644 --- a/bridge/monitor.c +++ b/bridge/monitor.c @@ -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; diff --git a/bridge/vlan.c b/bridge/vlan.c index 7e425428..8a2cc306 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -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,6 +622,25 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg) return 0; } +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]; @@ -680,7 +700,7 @@ static void print_vlan_opts(struct rtattr *a) __print_one_vlan_stats(&vstats); } -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) { struct br_vlan_msg *bvm = NLMSG_DATA(n); int len = n->nlmsg_len; @@ -722,7 +742,8 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor) unsigned short rta_type = a->rta_type & NLA_TYPE_MASK; /* skip unknown attributes */ - if (rta_type > BRIDGE_VLANDB_MAX) + if (rta_type > BRIDGE_VLANDB_MAX || + (global_only && rta_type != BRIDGE_VLANDB_GLOBAL_OPTIONS)) continue; if (vlan_rtm_cur_ifidx != bvm->ifindex) { @@ -737,6 +758,9 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor) case BRIDGE_VLANDB_ENTRY: print_vlan_opts(a); break; + case BRIDGE_VLANDB_GLOBAL_OPTIONS: + print_vlan_global_opts(a); + break; } close_json_object(); } @@ -746,7 +770,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) @@ -864,6 +893,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; @@ -908,6 +992,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 (strcmp(*argv, "show") == 0 || + strcmp(*argv, "lst") == 0 || + strcmp(*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); @@ -926,6 +1026,8 @@ int do_vlan(int argc, char **argv) } if (matches(*argv, "set") == 0) return vlan_option_set(argc-1, argv+1); + if (strcmp(*argv, "global") == 0) + return vlan_global(argc-1, argv+1); if (matches(*argv, "help") == 0) usage(); } else { diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index eec7df43..9ec4cb1d 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -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