All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.