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 timestamp;
extern int compress_vlans;
extern int json_output;
extern struct rtnl_handle rth;

View File

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

View File

@ -7,6 +7,7 @@
#include <netinet/in.h>
#include <linux/if_bridge.h>
#include <linux/if_ether.h>
#include <json_writer.h>
#include <string.h>
#include "libnetlink.h"
@ -15,6 +16,8 @@
static unsigned int filter_index, filter_vlan;
json_writer_t *jw_global = NULL;
static void usage(void)
{
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;
}
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,
struct nlmsghdr *n,
void *arg)
@ -166,6 +191,8 @@ static int print_vlan(const struct sockaddr_nl *who,
struct ifinfomsg *ifm = NLMSG_DATA(n);
int len = n->nlmsg_len;
struct rtattr *tb[IFLA_MAX+1];
bool vlan_flags;
char flags[80];
if (n->nlmsg_type != RTM_NEWLINK) {
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;
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)) {
struct bridge_vlan_info *vinfo;
int vcheck_ret;
@ -218,20 +246,58 @@ static int print_vlan(const struct sockaddr_nl *who,
continue;
if (filter_vlan)
fprintf(fp, "%s",
ll_index_to_name(ifm->ifi_index));
fprintf(fp, "\t %hu", last_vid_start);
if (last_vid_start != vinfo->vid)
fprintf(fp, "-%hu", vinfo->vid);
if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
fprintf(fp, " PVID");
if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
fprintf(fp, " Egress Untagged");
fprintf(fp, "\n");
print_vlan_port(fp, ifm->ifi_index);
if (jw_global) {
jsonw_start_object(jw_global);
jsonw_uint_field(jw_global, "vlan",
last_vid_start);
if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
continue;
} else {
fprintf(fp, "\t %hu", last_vid_start);
}
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)
fprintf(fp, "\n");
if (!filter_vlan) {
if (jw_global)
jsonw_end_array(jw_global);
else
fprintf(fp, "\n");
}
fflush(fp);
return 0;
}
@ -271,12 +337,27 @@ static int vlan_show(int argc, char **argv)
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) {
fprintf(stderr, "Dump ternminated\n");
exit(1);
}
if (jw_global) {
jsonw_end_object(jw_global);
jsonw_destroy(&jw_global);
}
return 0;
}