* [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show
@ 2016-06-21 6:39 Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object Roopa Prabhu
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Roopa Prabhu <roopa@cumulusnetworks.com>
This patch series adds json support for a few bridge show commands.
We plan to follow up with json support for additional commands soon.
Anuradha Karuppiah (3):
json_writer: allow base json data type to be array or object
bridge: add json support for bridge fdb show
bridge: add json schema for bridge fdb show
Roopa Prabhu (2):
bridge: add json support for bridge vlan show
bridge: update man page
v2 - change vlan flags to an array as suggested by toshiaki
v3 - no change. resubmitting as requested by stephen
bridge/br_common.h | 1 +
bridge/bridge.c | 3 +
bridge/fdb.c | 201 +++++++++++++++++++++++++++++++++---------
bridge/vlan.c | 93 ++++++++++++++++++-
include/json_writer.h | 5 +-
lib/json_writer.c | 39 +++++++-
man/man8/bridge.8 | 9 +-
misc/ifstat.c | 6 +-
misc/lnstat.c | 2 +-
misc/nstat.c | 4 +-
schema/bridge_fdb_schema.json | 62 +++++++++++++
11 files changed, 365 insertions(+), 60 deletions(-)
create mode 100644 schema/bridge_fdb_schema.json
--
1.9.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
@ 2016-06-21 6:39 ` Roopa Prabhu
2016-06-21 16:12 ` Stephen Hemminger
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 2/5] bridge: add json support for bridge vlan show Roopa Prabhu
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This patch adds a type qualifier to json_writer. Type can be a
json object or array. This can be extended to other types like
json-string, json-number etc in the future.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
---
include/json_writer.h | 5 +++--
lib/json_writer.c | 39 +++++++++++++++++++++++++++++++++++----
misc/ifstat.c | 6 +++---
misc/lnstat.c | 2 +-
misc/nstat.c | 4 ++--
5 files changed, 44 insertions(+), 12 deletions(-)
diff --git a/include/json_writer.h b/include/json_writer.h
index ab9a008..e04a40a 100644
--- a/include/json_writer.h
+++ b/include/json_writer.h
@@ -21,8 +21,9 @@
/* Opaque class structure */
typedef struct json_writer json_writer_t;
-/* Create a new JSON stream */
-json_writer_t *jsonw_new(FILE *f);
+/* Create a new JSON stream with data type */
+json_writer_t *jsonw_new_object(FILE *f);
+json_writer_t *jsonw_new_array(FILE *f);
/* End output to JSON stream */
void jsonw_destroy(json_writer_t **self_p);
diff --git a/lib/json_writer.c b/lib/json_writer.c
index 2af16e1..420cd87 100644
--- a/lib/json_writer.c
+++ b/lib/json_writer.c
@@ -22,11 +22,17 @@
#include "json_writer.h"
+enum jsonw_data_type {
+ JSONW_TYPE_OBJECT,
+ JSONW_TYPE_ARRAY
+};
+
struct json_writer {
FILE *out; /* output file */
unsigned depth; /* nesting */
bool pretty; /* optional whitepace */
char sep; /* either nul or comma */
+ int type; /* currently either object or array */
};
/* indentation for pretty print */
@@ -94,7 +100,7 @@ static void jsonw_puts(json_writer_t *self, const char *str)
}
/* Create a new JSON stream */
-json_writer_t *jsonw_new(FILE *f)
+static json_writer_t *jsonw_new(FILE *f, int type)
{
json_writer_t *self = malloc(sizeof(*self));
if (self) {
@@ -102,11 +108,29 @@ json_writer_t *jsonw_new(FILE *f)
self->depth = 0;
self->pretty = false;
self->sep = '\0';
- putc('{', self->out);
+ self->type = type;
+ switch (self->type) {
+ case JSONW_TYPE_OBJECT:
+ putc('{', self->out);
+ break;
+ case JSONW_TYPE_ARRAY:
+ putc('[', self->out);
+ break;
+ }
}
return self;
}
+json_writer_t *jsonw_new_object(FILE *f)
+{
+ return jsonw_new(f, JSONW_TYPE_OBJECT);
+}
+
+json_writer_t *jsonw_new_array(FILE *f)
+{
+ return jsonw_new(f, JSONW_TYPE_ARRAY);
+}
+
/* End output to JSON stream */
void jsonw_destroy(json_writer_t **self_p)
{
@@ -114,7 +138,14 @@ void jsonw_destroy(json_writer_t **self_p)
assert(self->depth == 0);
jsonw_eol(self);
- fputs("}\n", self->out);
+ switch (self->type) {
+ case JSONW_TYPE_OBJECT:
+ fputs("}\n", self->out);
+ break;
+ case JSONW_TYPE_ARRAY:
+ fputs("]\n", self->out);
+ break;
+ }
fflush(self->out);
free(self);
*self_p = NULL;
@@ -267,7 +298,7 @@ void jsonw_null_field(json_writer_t *self, const char *prop)
#ifdef TEST
int main(int argc, char **argv)
{
- json_writer_t *wr = jsonw_new(stdout);
+ json_writer_t *wr = jsonw_new_object(stdout);
jsonw_pretty(wr, true);
jsonw_name(wr, "Vyatta");
diff --git a/misc/ifstat.c b/misc/ifstat.c
index abbb4e7..29aa63c 100644
--- a/misc/ifstat.c
+++ b/misc/ifstat.c
@@ -240,7 +240,7 @@ static void load_raw_table(FILE *fp)
static void dump_raw_db(FILE *fp, int to_hist)
{
- json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
+ json_writer_t *jw = json_output ? jsonw_new_object(fp) : NULL;
struct ifstat_ent *n, *h;
h = hist_db;
@@ -447,7 +447,7 @@ static void print_one_if(FILE *fp, const struct ifstat_ent *n,
static void dump_kern_db(FILE *fp)
{
- json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
+ json_writer_t *jw = json_output ? jsonw_new_object(fp) : NULL;
struct ifstat_ent *n;
if (jw) {
@@ -473,7 +473,7 @@ static void dump_kern_db(FILE *fp)
static void dump_incr_db(FILE *fp)
{
struct ifstat_ent *n, *h;
- json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
+ json_writer_t *jw = json_output ? jsonw_new_object(fp) : NULL;
h = hist_db;
if (jw) {
diff --git a/misc/lnstat.c b/misc/lnstat.c
index 659a01b..2988e9e 100644
--- a/misc/lnstat.c
+++ b/misc/lnstat.c
@@ -110,7 +110,7 @@ static void print_line(FILE *of, const struct lnstat_file *lnstat_files,
static void print_json(FILE *of, const struct lnstat_file *lnstat_files,
const struct field_params *fp)
{
- json_writer_t *jw = jsonw_new(of);
+ json_writer_t *jw = jsonw_new_object(of);
int i;
jsonw_start_object(jw);
diff --git a/misc/nstat.c b/misc/nstat.c
index a9e0f20..7ca6204 100644
--- a/misc/nstat.c
+++ b/misc/nstat.c
@@ -279,7 +279,7 @@ static void load_netstat(void)
static void dump_kern_db(FILE *fp, int to_hist)
{
- json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
+ json_writer_t *jw = json_output ? jsonw_new_object(fp) : NULL;
struct nstat_ent *n, *h;
h = hist_db;
@@ -323,7 +323,7 @@ static void dump_kern_db(FILE *fp, int to_hist)
static void dump_incr_db(FILE *fp)
{
- json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
+ json_writer_t *jw = json_output ? jsonw_new_object(fp) : NULL;
struct nstat_ent *n, *h;
h = hist_db;
--
1.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH iproute2 net-next v3 2/5] bridge: add json support for bridge vlan show
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object Roopa Prabhu
@ 2016-06-21 6:39 ` Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 3/5] bridge: add json support for bridge fdb show Roopa Prabhu
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Roopa Prabhu <roopa@cumulusnetworks.com>
$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>
---
bridge/br_common.h | 1 +
bridge/bridge.c | 5 ++-
bridge/vlan.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 97 insertions(+), 15 deletions(-)
diff --git a/bridge/br_common.h b/bridge/br_common.h
index 5ea45c9..c649e7d 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -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;
diff --git a/bridge/bridge.c b/bridge/bridge.c
index 72f153f..5ff038d 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -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++;
diff --git a/bridge/vlan.c b/bridge/vlan.c
index 717025a..fbf14c8 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -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,24 @@ static int vlan_show(int argc, char **argv)
exit(1);
}
- printf("port\tvlan ids\n");
+ if (json_output) {
+ jw_global = jsonw_new_object(stdout);
+ if (!jw_global) {
+ fprintf(stderr, "Error allocation json object\n");
+ exit(1);
+ }
+ } 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_destroy(&jw_global);
+
return 0;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH iproute2 net-next v3 3/5] bridge: add json support for bridge fdb show
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 2/5] bridge: add json support for bridge vlan show Roopa Prabhu
@ 2016-06-21 6:39 ` Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 4/5] bridge: add json schema " Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 5/5] bridge: update man page Roopa Prabhu
4 siblings, 0 replies; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
bridge/fdb.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 164 insertions(+), 43 deletions(-)
diff --git a/bridge/fdb.c b/bridge/fdb.c
index be849f9..c2bfeb2 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -21,6 +21,8 @@
#include <linux/neighbour.h>
#include <string.h>
#include <limits.h>
+#include <json_writer.h>
+#include <stdbool.h>
#include "libnetlink.h"
#include "br_common.h"
@@ -29,6 +31,8 @@
static unsigned int filter_index, filter_vlan;
+json_writer_t *jw_global;
+
static void usage(void)
{
fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
@@ -59,6 +63,15 @@ static const char *state_n2a(unsigned int s)
return buf;
}
+static void start_json_fdb_flags_array(bool *fdb_flags)
+{
+ if (*fdb_flags)
+ return;
+ jsonw_name(jw_global, "flags");
+ jsonw_start_array(jw_global);
+ *fdb_flags = true;
+}
+
int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = arg;
@@ -66,11 +79,12 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
int len = n->nlmsg_len;
struct rtattr *tb[NDA_MAX+1];
__u16 vid = 0;
+ bool fdb_flags = false;
+ const char *state_s;
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-
return 0;
}
@@ -86,6 +100,11 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (filter_index && filter_index != r->ndm_ifindex)
return 0;
+ if (jw_global) {
+ jsonw_pretty(jw_global, 1);
+ jsonw_start_object(jw_global);
+ }
+
parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
@@ -95,40 +114,75 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (filter_vlan && filter_vlan != vid)
return 0;
- if (n->nlmsg_type == RTM_DELNEIGH)
- fprintf(fp, "Deleted ");
+ if (n->nlmsg_type == RTM_DELNEIGH) {
+ if (jw_global)
+ jsonw_string_field(jw_global, "opCode", "deleted");
+ else
+ fprintf(fp, "Deleted ");
+ }
if (tb[NDA_LLADDR]) {
SPRINT_BUF(b1);
- fprintf(fp, "%s ",
- ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
- RTA_PAYLOAD(tb[NDA_LLADDR]),
- ll_index_to_type(r->ndm_ifindex),
- b1, sizeof(b1)));
+ ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+ RTA_PAYLOAD(tb[NDA_LLADDR]),
+ ll_index_to_type(r->ndm_ifindex),
+ b1, sizeof(b1));
+ if (jw_global)
+ jsonw_string_field(jw_global, "mac", b1);
+ else
+ fprintf(fp, "%s ", b1);
}
- if (!filter_index && r->ndm_ifindex)
- fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
+ if (!filter_index && r->ndm_ifindex) {
+ if (jw_global)
+ jsonw_string_field(jw_global, "dev",
+ ll_index_to_name(r->ndm_ifindex));
+ else
+ fprintf(fp, "dev %s ",
+ ll_index_to_name(r->ndm_ifindex));
+ }
if (tb[NDA_DST]) {
int family = AF_INET;
+ const char *abuf_s;
if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
family = AF_INET6;
- fprintf(fp, "dst %s ",
- format_host(family,
- RTA_PAYLOAD(tb[NDA_DST]),
- RTA_DATA(tb[NDA_DST])));
+ abuf_s = format_host(family,
+ RTA_PAYLOAD(tb[NDA_DST]),
+ RTA_DATA(tb[NDA_DST]));
+ if (jw_global)
+ jsonw_string_field(jw_global, "dst", abuf_s);
+ else
+ fprintf(fp, "dst %s ", abuf_s);
+ }
+
+ if (vid) {
+ if (jw_global)
+ jsonw_uint_field(jw_global, "vlan", vid);
+ else
+ fprintf(fp, "vlan %hu ", vid);
+ }
+
+ if (tb[NDA_PORT]) {
+ if (jw_global)
+ jsonw_uint_field(jw_global, "port",
+ ntohs(rta_getattr_u16(tb[NDA_PORT])));
+ else
+ fprintf(fp, "port %d ",
+ ntohs(rta_getattr_u16(tb[NDA_PORT])));
}
- if (vid)
- fprintf(fp, "vlan %hu ", vid);
+ if (tb[NDA_VNI]) {
+ if (jw_global)
+ jsonw_uint_field(jw_global, "vni",
+ rta_getattr_u32(tb[NDA_VNI]));
+ else
+ fprintf(fp, "vni %d ",
+ rta_getattr_u32(tb[NDA_VNI]));
+ }
- if (tb[NDA_PORT])
- fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT])));
- if (tb[NDA_VNI])
- fprintf(fp, "vni %d ", rta_getattr_u32(tb[NDA_VNI]));
if (tb[NDA_IFINDEX]) {
unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
@@ -136,37 +190,95 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
char ifname[IF_NAMESIZE];
if (!tb[NDA_LINK_NETNSID] &&
- if_indextoname(ifindex, ifname))
- fprintf(fp, "via %s ", ifname);
- else
- fprintf(fp, "via ifindex %u ", ifindex);
+ if_indextoname(ifindex, ifname)) {
+ if (jw_global)
+ jsonw_string_field(jw_global, "viaIf",
+ ifname);
+ else
+ fprintf(fp, "via %s ", ifname);
+ } else {
+ if (jw_global)
+ jsonw_uint_field(jw_global, "viaIfIndex",
+ ifindex);
+ else
+ fprintf(fp, "via ifindex %u ", ifindex);
+ }
}
}
- if (tb[NDA_LINK_NETNSID])
- fprintf(fp, "link-netnsid %d ",
- rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+
+ if (tb[NDA_LINK_NETNSID]) {
+ if (jw_global)
+ jsonw_uint_field(jw_global, "linkNetNsId",
+ rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+ else
+ fprintf(fp, "link-netnsid %d ",
+ rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+ }
if (show_stats && tb[NDA_CACHEINFO]) {
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
int hz = get_user_hz();
- fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
- ci->ndm_updated/hz);
+ if (jw_global) {
+ jsonw_uint_field(jw_global, "used",
+ ci->ndm_used/hz);
+ jsonw_uint_field(jw_global, "updated",
+ ci->ndm_updated/hz);
+ } else {
+ fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
+ ci->ndm_updated/hz);
+ }
+ }
+
+ if (jw_global) {
+ if (r->ndm_flags & NTF_SELF) {
+ start_json_fdb_flags_array(&fdb_flags);
+ jsonw_string(jw_global, "self");
+ }
+ if (r->ndm_flags & NTF_ROUTER) {
+ start_json_fdb_flags_array(&fdb_flags);
+ jsonw_string(jw_global, "router");
+ }
+ if (r->ndm_flags & NTF_EXT_LEARNED) {
+ start_json_fdb_flags_array(&fdb_flags);
+ jsonw_string(jw_global, "offload");
+ }
+ if (r->ndm_flags & NTF_MASTER)
+ jsonw_string(jw_global, "master");
+ if (fdb_flags)
+ jsonw_end_array(jw_global);
+
+ if (tb[NDA_MASTER])
+ jsonw_string_field(jw_global,
+ "master",
+ ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
+
+ } else {
+ if (r->ndm_flags & NTF_SELF)
+ fprintf(fp, "self ");
+ if (r->ndm_flags & NTF_ROUTER)
+ fprintf(fp, "router ");
+ if (r->ndm_flags & NTF_EXT_LEARNED)
+ fprintf(fp, "offload ");
+ if (tb[NDA_MASTER]) {
+ fprintf(fp, "master %s ",
+ ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
+ } else if (r->ndm_flags & NTF_MASTER) {
+ fprintf(fp, "master ");
+ }
+ }
+
+ state_s = state_n2a(r->ndm_state);
+ if (jw_global) {
+ if (state_s[0])
+ jsonw_string_field(jw_global, "state", state_s);
+
+ jsonw_end_object(jw_global);
+ } else {
+ fprintf(fp, "%s\n", state_s);
+
+ fflush(fp);
}
- if (r->ndm_flags & NTF_SELF)
- fprintf(fp, "self ");
- if (tb[NDA_MASTER])
- fprintf(fp, "master %s ",
- ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
- else if (r->ndm_flags & NTF_MASTER)
- fprintf(fp, "master ");
- if (r->ndm_flags & NTF_ROUTER)
- fprintf(fp, "router ");
- if (r->ndm_flags & NTF_EXT_LEARNED)
- fprintf(fp, "offload ");
-
- fprintf(fp, "%s\n", state_n2a(r->ndm_state));
- fflush(fp);
return 0;
}
@@ -233,10 +345,19 @@ static int fdb_show(int argc, char **argv)
exit(1);
}
+ if (json_output) {
+ jw_global = jsonw_new_array(stdout);
+ if (!jw_global) {
+ fprintf(stderr, "Error allocation json object\n");
+ exit(1);
+ }
+ }
if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
+ if (jw_global)
+ jsonw_destroy(&jw_global);
return 0;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH iproute2 net-next v3 4/5] bridge: add json schema for bridge fdb show
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
` (2 preceding siblings ...)
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 3/5] bridge: add json support for bridge fdb show Roopa Prabhu
@ 2016-06-21 6:39 ` Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 5/5] bridge: update man page Roopa Prabhu
4 siblings, 0 replies; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
we think storing the schema file for the json
format will be useful.
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
---
schema/bridge_fdb_schema.json | 62 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100644 schema/bridge_fdb_schema.json
diff --git a/schema/bridge_fdb_schema.json b/schema/bridge_fdb_schema.json
new file mode 100644
index 0000000..3e5be8d
--- /dev/null
+++ b/schema/bridge_fdb_schema.json
@@ -0,0 +1,62 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "description": "bridge fdb show",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "dev": {
+ "type": "string"
+ },
+ "dst": {
+ "description" : "host name or ip address",
+ "type": "string"
+ },
+ "flags": {
+ "type": "array",
+ "items": {
+ "enum": ["self", "master", "router", "offload"]
+ },
+ "uniqueItems": true
+ },
+ "linkNetNsId": {
+ "type": "integer"
+ },
+ "mac": {
+ "type": "string"
+ },
+ "master": {
+ "type": "string"
+ },
+ "opCode": {
+ "description" : "used to indicate fdb entry del",
+ "enum": ["deleted"]
+ },
+ "port": {
+ "type": "integer"
+ },
+ "state": {
+ "description" : "permanent, static, stale, state=#x",
+ "type": "string"
+ },
+ "updated": {
+ "type": "integer"
+ },
+ "used": {
+ "type": "integer"
+ },
+ "viaIf": {
+ "type": "string"
+ },
+ "viaIfIndex": {
+ "type": "integer"
+ },
+ "vlan": {
+ "type": "integer"
+ },
+ "vni": {
+ "type": "integer"
+ }
+ }
+ }
+}
--
1.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH iproute2 net-next v3 5/5] bridge: update man page
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
` (3 preceding siblings ...)
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 4/5] bridge: add json schema " Roopa Prabhu
@ 2016-06-21 6:39 ` Roopa Prabhu
4 siblings, 0 replies; 9+ messages in thread
From: Roopa Prabhu @ 2016-06-21 6:39 UTC (permalink / raw)
To: stephen, netdev; +Cc: anuradhak, nikolay, julien
From: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
man/man8/bridge.8 | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 08e8a5b..abaee63 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -20,8 +20,9 @@ bridge \- show / manipulate bridge addresses and devices
.IR OPTIONS " := { "
\fB\-V\fR[\fIersion\fR] |
\fB\-s\fR[\fItatistics\fR] |
-\fB\-n\fR[\fIetns\fR] name }
-\fB\-b\fR[\fIatch\fR] filename }
+\fB\-n\fR[\fIetns\fR] name |
+\fB\-b\fR[\fIatch\fR] filename |
+\fB\-j\fR[\fIson\fR] }
.ti -8
.BR "bridge link set"
@@ -153,6 +154,10 @@ Don't terminate bridge command on errors in batch mode.
If there were any errors during execution of the commands, the application
return code will be non zero.
+.TP
+.BR "\-json"
+Display results in JSON format. Currently available for vlan and fdb.
+
.SH BRIDGE - COMMAND SYNTAX
.SS
--
1.9.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object Roopa Prabhu
@ 2016-06-21 16:12 ` Stephen Hemminger
2016-06-21 16:24 ` Anuradha Karuppiah
0 siblings, 1 reply; 9+ messages in thread
From: Stephen Hemminger @ 2016-06-21 16:12 UTC (permalink / raw)
To: Roopa Prabhu; +Cc: netdev, anuradhak, nikolay, julien
On Mon, 20 Jun 2016 23:39:43 -0700
Roopa Prabhu <roopa@cumulusnetworks.com> wrote:
> From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
>
> This patch adds a type qualifier to json_writer. Type can be a
> json object or array. This can be extended to other types like
> json-string, json-number etc in the future.
>
> Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Since json writer is not used in many places yet, why not just
get rid of the automatic object in the constructor.
diff --git a/lib/json_writer.c b/lib/json_writer.c
index 2af16e1..5e588d8 100644
--- a/lib/json_writer.c
+++ b/lib/json_writer.c
@@ -102,7 +102,6 @@ json_writer_t *jsonw_new(FILE *f)
self->depth = 0;
self->pretty = false;
self->sep = '\0';
- putc('{', self->out);
}
return self;
}
@@ -114,7 +113,6 @@ void jsonw_destroy(json_writer_t **self_p)
assert(self->depth == 0);
jsonw_eol(self);
- fputs("}\n", self->out);
fflush(self->out);
free(self);
*self_p = NULL;
diff --git a/misc/ifstat.c b/misc/ifstat.c
index abbb4e7..d9a7e50 100644
--- a/misc/ifstat.c
+++ b/misc/ifstat.c
@@ -246,7 +246,6 @@ static void dump_raw_db(FILE *fp, int to_hist)
h = hist_db;
if (jw) {
jsonw_pretty(jw, pretty);
- jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
fprintf(fp, "#%s\n", info_source);
@@ -452,7 +451,6 @@ static void dump_kern_db(FILE *fp)
if (jw) {
jsonw_pretty(jw, pretty);
- jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
print_head(fp);
@@ -466,8 +464,10 @@ static void dump_kern_db(FILE *fp)
else
print_one_if(fp, n, n->val);
}
- if (json_output)
- fprintf(fp, "\n} }\n");
+ if (jw) {
+ jsonw_end_object(jw);
+ jsonw_destroy(&jw);
+ }
}
static void dump_incr_db(FILE *fp)
@@ -478,7 +478,6 @@ static void dump_incr_db(FILE *fp)
h = hist_db;
if (jw) {
jsonw_pretty(jw, pretty);
- jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
print_head(fp);
diff --git a/misc/nstat.c b/misc/nstat.c
index a9e0f20..411cd87 100644
--- a/misc/nstat.c
+++ b/misc/nstat.c
@@ -285,7 +285,6 @@ static void dump_kern_db(FILE *fp, int to_hist)
h = hist_db;
if (jw) {
jsonw_pretty(jw, pretty);
- jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
fprintf(fp, "#%s\n", info_source);
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object
2016-06-21 16:12 ` Stephen Hemminger
@ 2016-06-21 16:24 ` Anuradha Karuppiah
2016-06-21 16:52 ` Stephen Hemminger
0 siblings, 1 reply; 9+ messages in thread
From: Anuradha Karuppiah @ 2016-06-21 16:24 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Roopa Prabhu, netdev, Nikolay Aleksandrov, Julien Fortin
On Tue, Jun 21, 2016 at 9:12 AM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
> On Mon, 20 Jun 2016 23:39:43 -0700
> Roopa Prabhu <roopa@cumulusnetworks.com> wrote:
>
>> From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
>>
>> This patch adds a type qualifier to json_writer. Type can be a
>> json object or array. This can be extended to other types like
>> json-string, json-number etc in the future.
>>
>> Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
>
> Since json writer is not used in many places yet, why not just
> get rid of the automatic object in the constructor.
I wanted to force the external api to start with an json-object or
json-array. It reduces the chance of mistakes vs. a typeless
constructor. With a typeless constructor you can accidentally end up
with a json output that doesn't pass json lint; especially if optional
params are being suppressed at different places.
>
>
>
> diff --git a/lib/json_writer.c b/lib/json_writer.c
> index 2af16e1..5e588d8 100644
> --- a/lib/json_writer.c
> +++ b/lib/json_writer.c
> @@ -102,7 +102,6 @@ json_writer_t *jsonw_new(FILE *f)
> self->depth = 0;
> self->pretty = false;
> self->sep = '\0';
> - putc('{', self->out);
> }
> return self;
> }
> @@ -114,7 +113,6 @@ void jsonw_destroy(json_writer_t **self_p)
>
> assert(self->depth == 0);
> jsonw_eol(self);
> - fputs("}\n", self->out);
> fflush(self->out);
> free(self);
> *self_p = NULL;
> diff --git a/misc/ifstat.c b/misc/ifstat.c
> index abbb4e7..d9a7e50 100644
> --- a/misc/ifstat.c
> +++ b/misc/ifstat.c
> @@ -246,7 +246,6 @@ static void dump_raw_db(FILE *fp, int to_hist)
> h = hist_db;
> if (jw) {
> jsonw_pretty(jw, pretty);
> - jsonw_name(jw, info_source);
> jsonw_start_object(jw);
> } else
> fprintf(fp, "#%s\n", info_source);
> @@ -452,7 +451,6 @@ static void dump_kern_db(FILE *fp)
>
> if (jw) {
> jsonw_pretty(jw, pretty);
> - jsonw_name(jw, info_source);
> jsonw_start_object(jw);
> } else
> print_head(fp);
> @@ -466,8 +464,10 @@ static void dump_kern_db(FILE *fp)
> else
> print_one_if(fp, n, n->val);
> }
> - if (json_output)
> - fprintf(fp, "\n} }\n");
> + if (jw) {
> + jsonw_end_object(jw);
> + jsonw_destroy(&jw);
> + }
> }
>
> static void dump_incr_db(FILE *fp)
> @@ -478,7 +478,6 @@ static void dump_incr_db(FILE *fp)
> h = hist_db;
> if (jw) {
> jsonw_pretty(jw, pretty);
> - jsonw_name(jw, info_source);
> jsonw_start_object(jw);
> } else
> print_head(fp);
> diff --git a/misc/nstat.c b/misc/nstat.c
> index a9e0f20..411cd87 100644
> --- a/misc/nstat.c
> +++ b/misc/nstat.c
> @@ -285,7 +285,6 @@ static void dump_kern_db(FILE *fp, int to_hist)
> h = hist_db;
> if (jw) {
> jsonw_pretty(jw, pretty);
> - jsonw_name(jw, info_source);
> jsonw_start_object(jw);
> } else
> fprintf(fp, "#%s\n", info_source);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object
2016-06-21 16:24 ` Anuradha Karuppiah
@ 2016-06-21 16:52 ` Stephen Hemminger
0 siblings, 0 replies; 9+ messages in thread
From: Stephen Hemminger @ 2016-06-21 16:52 UTC (permalink / raw)
To: Anuradha Karuppiah
Cc: Roopa Prabhu, netdev, Nikolay Aleksandrov, Julien Fortin
On Tue, 21 Jun 2016 09:24:50 -0700
Anuradha Karuppiah <anuradhak@cumulusnetworks.com> wrote:
> On Tue, Jun 21, 2016 at 9:12 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> > On Mon, 20 Jun 2016 23:39:43 -0700
> > Roopa Prabhu <roopa@cumulusnetworks.com> wrote:
> >
> >> From: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
> >>
> >> This patch adds a type qualifier to json_writer. Type can be a
> >> json object or array. This can be extended to other types like
> >> json-string, json-number etc in the future.
> >>
> >> Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
> >
> > Since json writer is not used in many places yet, why not just
> > get rid of the automatic object in the constructor.
>
> I wanted to force the external api to start with an json-object or
> json-array. It reduces the chance of mistakes vs. a typeless
> constructor. With a typeless constructor you can accidentally end up
> with a json output that doesn't pass json lint; especially if optional
> params are being suppressed at different places.
Still, this is not how jsonwriter works in .NET, Android, or Java.
It is easily confusing to developers if similar API's behave
differently. Kind of like if printf() always appended a new line
on some platforms.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2016-06-21 17:00 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-21 6:39 [PATCH iproute2 net-next v3 0/5] bridge: json support for fdb and vlan show Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 1/5] json_writer: allow base json data type to be array or object Roopa Prabhu
2016-06-21 16:12 ` Stephen Hemminger
2016-06-21 16:24 ` Anuradha Karuppiah
2016-06-21 16:52 ` Stephen Hemminger
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 2/5] bridge: add json support for bridge vlan show Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 3/5] bridge: add json support for bridge fdb show Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 4/5] bridge: add json schema " Roopa Prabhu
2016-06-21 6:39 ` [PATCH iproute2 net-next v3 5/5] bridge: update man page Roopa Prabhu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.