bridge: add json support for bridge vlan show

$bridge -c vlan show
port	vlan ids
swp1	 1 PVID Egress Untagged
	 10-13

swp2	 1 PVID Egress Untagged
	 10-13

br0	 1 PVID Egress Untagged

$bridge  -json vlan show
{
    "swp1": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 10
        },{
            "vlan": 11
        },{
            "vlan": 12
        },{
            "vlan": 13
        }
    ],
    "swp2": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 10
        },{
            "vlan": 11
        },{
            "vlan": 12
        },{
            "vlan": 13
        }
    ],
    "br0": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        }
    ]
}

$bridge -c -json vlan show
{
    "swp1": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 10,
            "vlanEnd": 13
        }
    ],
    "swp2": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 10,
            "vlanEnd": 13
        }
    ],
    "br0": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        }
    ]
}

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
This commit is contained in:
Roopa Prabhu 2016-06-22 06:45:52 -07:00 committed by Stephen Hemminger
parent d721a14590
commit d82a49ce85
3 changed files with 100 additions and 15 deletions

View File

@ -23,4 +23,5 @@ extern int show_stats;
extern int show_details; extern int show_details;
extern int timestamp; extern int timestamp;
extern int compress_vlans; extern int compress_vlans;
extern int json_output;
extern struct rtnl_handle rth; extern struct rtnl_handle rth;

View File

@ -23,6 +23,7 @@ int oneline;
int show_stats; int show_stats;
int show_details; int show_details;
int compress_vlans; int compress_vlans;
int json_output;
int timestamp; int timestamp;
char *batch_file; char *batch_file;
int force; int force;
@ -38,7 +39,7 @@ static void usage(void)
"where OBJECT := { link | fdb | mdb | vlan | monitor }\n" "where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
" -o[neline] | -t[imestamp] | -n[etns] name |\n" " -o[neline] | -t[imestamp] | -n[etns] name |\n"
" -c[ompressvlans] }\n"); " -c[ompressvlans] -j{son} }\n");
exit(-1); exit(-1);
} }
@ -173,6 +174,8 @@ main(int argc, char **argv)
++compress_vlans; ++compress_vlans;
} else if (matches(opt, "-force") == 0) { } else if (matches(opt, "-force") == 0) {
++force; ++force;
} else if (matches(opt, "-json") == 0) {
++json_output;
} else if (matches(opt, "-batch") == 0) { } else if (matches(opt, "-batch") == 0) {
argc--; argc--;
argv++; argv++;

View File

@ -7,6 +7,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <json_writer.h>
#include <string.h> #include <string.h>
#include "libnetlink.h" #include "libnetlink.h"
@ -15,6 +16,8 @@
static unsigned int filter_index, filter_vlan; static unsigned int filter_index, filter_vlan;
json_writer_t *jw_global = NULL;
static void usage(void) 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");
@ -158,6 +161,28 @@ static int filter_vlan_check(struct bridge_vlan_info *vinfo)
return 1; return 1;
} }
static void print_vlan_port(FILE *fp, int ifi_index)
{
if (jw_global) {
jsonw_pretty(jw_global, 1);
jsonw_name(jw_global,
ll_index_to_name(ifi_index));
jsonw_start_array(jw_global);
} else {
fprintf(fp, "%s",
ll_index_to_name(ifi_index));
}
}
static void start_json_vlan_flags_array(bool *vlan_flags)
{
if (*vlan_flags)
return;
jsonw_name(jw_global, "flags");
jsonw_start_array(jw_global);
*vlan_flags = true;
}
static int print_vlan(const struct sockaddr_nl *who, static int print_vlan(const struct sockaddr_nl *who,
struct nlmsghdr *n, struct nlmsghdr *n,
void *arg) void *arg)
@ -166,6 +191,8 @@ static int print_vlan(const struct sockaddr_nl *who,
struct ifinfomsg *ifm = NLMSG_DATA(n); struct ifinfomsg *ifm = NLMSG_DATA(n);
int len = n->nlmsg_len; int len = n->nlmsg_len;
struct rtattr *tb[IFLA_MAX+1]; struct rtattr *tb[IFLA_MAX+1];
bool vlan_flags;
char flags[80];
if (n->nlmsg_type != RTM_NEWLINK) { if (n->nlmsg_type != RTM_NEWLINK) {
fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
@ -199,7 +226,8 @@ static int print_vlan(const struct sockaddr_nl *who,
__u16 last_vid_start = 0; __u16 last_vid_start = 0;
if (!filter_vlan) if (!filter_vlan)
fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); print_vlan_port(fp, ifm->ifi_index);
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
struct bridge_vlan_info *vinfo; struct bridge_vlan_info *vinfo;
int vcheck_ret; int vcheck_ret;
@ -218,20 +246,58 @@ static int print_vlan(const struct sockaddr_nl *who,
continue; continue;
if (filter_vlan) if (filter_vlan)
fprintf(fp, "%s", print_vlan_port(fp, ifm->ifi_index);
ll_index_to_name(ifm->ifi_index)); if (jw_global) {
fprintf(fp, "\t %hu", last_vid_start); jsonw_start_object(jw_global);
if (last_vid_start != vinfo->vid) jsonw_uint_field(jw_global, "vlan",
fprintf(fp, "-%hu", vinfo->vid); last_vid_start);
if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
fprintf(fp, " PVID"); continue;
if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) } else {
fprintf(fp, " Egress Untagged"); fprintf(fp, "\t %hu", last_vid_start);
fprintf(fp, "\n"); }
if (last_vid_start != vinfo->vid) {
if (jw_global)
jsonw_uint_field(jw_global, "vlanEnd",
vinfo->vid);
else
fprintf(fp, "-%hu", vinfo->vid);
}
if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
if (jw_global) {
start_json_vlan_flags_array(&vlan_flags);
jsonw_string(jw_global, "PVID");
} else {
fprintf(fp, " PVID");
}
}
if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
if (jw_global) {
start_json_vlan_flags_array(&vlan_flags);
jsonw_string(jw_global,
"Egress Untagged");
} else {
fprintf(fp, " Egress Untagged");
}
}
if (vlan_flags) {
jsonw_end_array(jw_global);
vlan_flags = false;
}
if (jw_global)
jsonw_end_object(jw_global);
else
fprintf(fp, "\n");
} }
} }
if (!filter_vlan) if (!filter_vlan) {
fprintf(fp, "\n"); if (jw_global)
jsonw_end_array(jw_global);
else
fprintf(fp, "\n");
}
fflush(fp); fflush(fp);
return 0; return 0;
} }
@ -271,12 +337,27 @@ static int vlan_show(int argc, char **argv)
exit(1); exit(1);
} }
printf("port\tvlan ids\n"); if (json_output) {
jw_global = jsonw_new(stdout);
if (!jw_global) {
fprintf(stderr, "Error allocation json object\n");
exit(1);
}
jsonw_start_object(jw_global);
} else {
printf("port\tvlan ids\n");
}
if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) { if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
fprintf(stderr, "Dump ternminated\n"); fprintf(stderr, "Dump ternminated\n");
exit(1); exit(1);
} }
if (jw_global) {
jsonw_end_object(jw_global);
jsonw_destroy(&jw_global);
}
return 0; return 0;
} }