summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c54
-rw-r--r--bgpd/bgp_aspath.h5
-rw-r--r--bgpd/bgp_community.c48
-rw-r--r--bgpd/bgp_community.h5
-rw-r--r--bgpd/bgp_damp.c19
-rw-r--r--bgpd/bgp_damp.h2
-rw-r--r--bgpd/bgp_open.h2
-rw-r--r--bgpd/bgp_route.c638
-rw-r--r--bgpd/bgp_route.h2
-rw-r--r--bgpd/bgp_vty.c176
-rw-r--r--bgpd/bgpd.c2
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/json.c59
-rw-r--r--lib/json.h38
14 files changed, 578 insertions, 476 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 04ef87d693..a270d8cd76 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -99,6 +99,14 @@ assegment_data_new (int num)
return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
}
+const char *aspath_segment_type_str[] = {
+ "as-invalid",
+ "as-set",
+ "as-sequence",
+ "as-confed-sequence",
+ "as-confed-set"
+};
+
/* Get a new segment. Note that 0 is an allowed length,
* and will result in a segment with no allocated data segment.
* the caller should immediately assign data to the segment, as the segment
@@ -326,6 +334,13 @@ aspath_free (struct aspath *aspath)
assegment_free_all (aspath->segments);
if (aspath->str)
XFREE (MTYPE_AS_STR, aspath->str);
+
+ if (aspath->json)
+ {
+ json_object_free(aspath->json);
+ aspath->json = NULL;
+ }
+
XFREE (MTYPE_AS_PATH, aspath);
}
@@ -500,10 +515,19 @@ aspath_make_str_count (struct aspath *as)
int str_size;
int len = 0;
char *str_buf;
+ json_object *jaspath_segments = NULL;
+ json_object *jseg = NULL;
+ json_object *jseg_list = NULL;
+
+ as->json = json_object_new_object();
+ jaspath_segments = json_object_new_array();
/* Empty aspath. */
if (!as->segments)
{
+ json_object_string_add(as->json, "string", "Local");
+ json_object_object_add(as->json, "segments", jaspath_segments);
+ json_object_int_add(as->json, "length", 0);
as->str = XMALLOC (MTYPE_AS_STR, 1);
as->str[0] = '\0';
as->str_len = 0;
@@ -546,6 +570,8 @@ aspath_make_str_count (struct aspath *as)
XFREE (MTYPE_AS_STR, str_buf);
as->str = NULL;
as->str_len = 0;
+ json_object_free(as->json);
+ as->json = NULL;
return;
}
@@ -571,15 +597,24 @@ aspath_make_str_count (struct aspath *as)
len += snprintf (str_buf + len, str_size - len,
"%c",
aspath_delimiter_char (seg->type, AS_SEG_START));
+
+ jseg_list = json_object_new_array();
/* write out the ASNs, with their seperators, bar the last one*/
for (i = 0; i < seg->length; i++)
{
+ json_object_array_add(jseg_list, json_object_new_int(seg->as[i]));
+
len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
if (i < (seg->length - 1))
len += snprintf (str_buf + len, str_size - len, "%c", seperator);
}
+
+ jseg = json_object_new_object();
+ json_object_string_add(jseg, "type", aspath_segment_type_str[seg->type]);
+ json_object_object_add(jseg, "list", jseg_list);
+ json_object_array_add(jaspath_segments, jseg);
if (seg->type != AS_SEQUENCE)
len += snprintf (str_buf + len, str_size - len, "%c",
@@ -596,6 +631,9 @@ aspath_make_str_count (struct aspath *as)
as->str = str_buf;
as->str_len = len;
+ json_object_string_add(as->json, "string", str_buf);
+ json_object_object_add(as->json, "segments", jaspath_segments);
+ json_object_int_add(as->json, "length", aspath_count_hops (as));
return;
}
@@ -604,6 +642,13 @@ aspath_str_update (struct aspath *as)
{
if (as->str)
XFREE (MTYPE_AS_STR, as->str);
+
+ if (as->json)
+ {
+ json_object_free(as->json);
+ as->json = NULL;
+ }
+
aspath_make_str_count (as);
}
@@ -637,6 +682,7 @@ aspath_dup (struct aspath *aspath)
struct aspath *new;
new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+ new->json = NULL;
if (aspath->segments)
new->segments = assegment_dup_all (aspath->segments);
@@ -675,6 +721,7 @@ aspath_hash_alloc (void *arg)
new->segments = aspath->segments;
new->str = aspath->str;
new->str_len = aspath->str_len;
+ new->json = aspath->json;
return new;
}
@@ -1239,6 +1286,7 @@ aspath_remove_private_asns (struct aspath *aspath)
new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+ new->json = NULL;
new_seg = NULL;
last_new_seg = NULL;
seg = aspath->segments;
@@ -1628,7 +1676,11 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
}
if (!hops)
- return aspath_dup (as4path);
+ {
+ newpath = aspath_dup (as4path);
+ aspath_str_update(newpath);
+ return newpath;
+ }
if ( BGP_DEBUG(as4, AS4))
zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index ec2df042fd..faf3bc8eaf 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ASPATH_H
#define _QUAGGA_BGP_ASPATH_H
+#include "lib/json.h"
+
/* AS path segment type. */
#define AS_SET 1
#define AS_SEQUENCE 2
@@ -63,6 +65,9 @@ struct aspath
/* segment data */
struct assegment *segments;
+ /* AS path as a json object */
+ json_object *json;
+
/* String expression of AS path. This string is used by vty output
and AS path regular expression match. */
char *str;
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index f1997bd9ce..19e4954e16 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -44,6 +44,13 @@ community_free (struct community *com)
XFREE (MTYPE_COMMUNITY_VAL, com->val);
if (com->str)
XFREE (MTYPE_COMMUNITY_STR, com->str);
+
+ if (com->json)
+ {
+ json_object_free(com->json);
+ com->json = NULL;
+ }
+
XFREE (MTYPE_COMMUNITY, com);
}
@@ -170,6 +177,7 @@ community_uniq_sort (struct community *com)
return NULL;
new = community_new ();;
+ new->json = NULL;
for (i = 0; i < com->size; i++)
{
@@ -194,8 +202,8 @@ community_uniq_sort (struct community *com)
0xFFFFFF03 "local-AS"
For other values, "AS:VAL" format is used. */
-static char *
-community_com2str (struct community *com)
+static void
+set_community_string (struct community *com)
{
int i;
char *str;
@@ -205,16 +213,25 @@ community_com2str (struct community *com)
u_int32_t comval;
u_int16_t as;
u_int16_t val;
+ json_object *json_community_list = NULL;
+ json_object *json_string = NULL;
if (!com)
return NULL;
+ com->json = json_object_new_object();
+ json_community_list = json_object_new_array();
+
/* When communities attribute is empty. */
if (com->size == 0)
{
str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
str[0] = '\0';
- return str;
+
+ json_object_string_add(com->json, "string", "");
+ json_object_object_add(com->json, "list", json_community_list);
+ com->str = str;
+ return;
}
/* Memory allocation is time consuming work. So we calculate
@@ -266,30 +283,42 @@ community_com2str (struct community *com)
case COMMUNITY_INTERNET:
strcpy (pnt, "internet");
pnt += strlen ("internet");
+ json_string = json_object_new_string("internet");
+ json_object_array_add(json_community_list, json_string);
break;
case COMMUNITY_NO_EXPORT:
strcpy (pnt, "no-export");
pnt += strlen ("no-export");
+ json_string = json_object_new_string("no-export");
+ json_object_array_add(json_community_list, json_string);
break;
case COMMUNITY_NO_ADVERTISE:
strcpy (pnt, "no-advertise");
pnt += strlen ("no-advertise");
+ json_string = json_object_new_string("no-advertise");
+ json_object_array_add(json_community_list, json_string);
break;
case COMMUNITY_LOCAL_AS:
strcpy (pnt, "local-AS");
pnt += strlen ("local-AS");
+ json_string = json_object_new_string("local-AS");
+ json_object_array_add(json_community_list, json_string);
break;
default:
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
sprintf (pnt, "%u:%d", as, val);
+ json_string = json_object_new_string(pnt);
+ json_object_array_add(json_community_list, json_string);
pnt += strlen (pnt);
break;
}
}
*pnt = '\0';
- return str;
+ json_object_string_add(com->json, "string", str);
+ json_object_object_add(com->json, "list", json_community_list);
+ com->str = str;
}
/* Intern communities attribute. */
@@ -314,7 +343,7 @@ community_intern (struct community *com)
/* Make string. */
if (! find->str)
- find->str = community_com2str (find);
+ set_community_string (find);
return find;
}
@@ -383,9 +412,9 @@ community_str (struct community *com)
{
if (!com)
return NULL;
-
+
if (! com->str)
- com->str = community_com2str (com);
+ set_community_string (com);
return com->str;
}
@@ -599,7 +628,10 @@ community_str2com (const char *str)
case community_token_no_advertise:
case community_token_local_as:
if (com == NULL)
- com = community_new();
+ {
+ com = community_new();
+ com->json = NULL;
+ }
community_add_val (com, val);
break;
case community_token_unknown:
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index c73dab3045..257f7767b4 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_COMMUNITY_H
#define _QUAGGA_BGP_COMMUNITY_H
+#include "lib/json.h"
+
/* Communities attribute. */
struct community
{
@@ -33,6 +35,9 @@ struct community
/* Communities value. */
u_int32_t *val;
+ /* Communities as a json object */
+ json_object *json;
+
/* String of community attribute. This sring is used by vty output
and expanded community-list for regular expression match. */
char *str;
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 6df3911978..fad3ea3c77 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -20,7 +20,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include <zebra.h>
#include <math.h>
-#include <json/json.h>
#include "prefix.h"
#include "memory.h"
@@ -587,8 +586,6 @@ bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo,
time_t t_now, t_diff;
char timebuf[BGP_UPTIME_LEN];
int penalty;
- json_object *json_int;
- json_object *json_string;
if (!binfo->extra)
return;
@@ -608,20 +605,16 @@ bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo,
if (json_path)
{
- json_int = json_object_new_int(penalty);
- json_object_object_add(json_path, "dampening-penalty", json_int);
-
- json_int = json_object_new_int(bdi->flap);
- json_object_object_add(json_path, "dampening-flap-count", json_int);
-
- json_string = json_object_new_string(peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
- json_object_object_add(json_path, "dampening-flap-period", json_string);
+ json_object_int_add(json_path, "dampening-penalty", penalty);
+ json_object_int_add(json_path, "dampening-flap-count", bdi->flap);
+ json_object_string_add(json_path, "dampening-flap-period",
+ peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
&& ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
{
- json_string = json_object_new_string(bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
- json_object_object_add(json_path, "dampening-reuse-in", json_string);
+ json_object_string_add(json_path, "dampening-reuse-in",
+ bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
}
}
else
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 9d4fcb332d..31c6c307ad 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -21,7 +21,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_DAMP_H
#define _QUAGGA_BGP_DAMP_H
-#include <json/json.h>
+#include "lib/json.h"
/* Structure maintained on a per-route basis. */
struct bgp_damp_info
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 6ef857284e..185218f729 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -21,8 +21,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_OPEN_H
#define _QUAGGA_BGP_OPEN_H
-#include <json/json.h>
-
/* Standard header for capability TLV */
struct capability_header
{
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e892501125..bc203d4400 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -19,7 +19,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <zebra.h>
-#include <json/json.h>
#include "prefix.h"
#include "linklist.h"
@@ -6509,44 +6508,41 @@ static void
route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo,
json_object *json_path)
{
- json_object *json_boolean_true;
-
if (json_path)
{
- json_boolean_true = json_object_new_boolean(1);
/* Route status display. */
if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
- json_object_object_add(json_path, "removed", json_boolean_true);
+ json_object_boolean_true_add(json_path, "removed");
if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
- json_object_object_add(json_path, "stale", json_boolean_true);
+ json_object_boolean_true_add(json_path, "stale");
if (binfo->extra && binfo->extra->suppress)
- json_object_object_add(json_path, "suppressed", json_boolean_true);
+ json_object_boolean_true_add(json_path, "suppressed");
if (CHECK_FLAG (binfo->flags, BGP_INFO_VALID) &&
! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
- json_object_object_add(json_path, "valid", json_boolean_true);
+ json_object_boolean_true_add(json_path, "valid");
/* Selected */
if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
- json_object_object_add(json_path, "history", json_boolean_true);
+ json_object_boolean_true_add(json_path, "history");
if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
- json_object_object_add(json_path, "damped", json_boolean_true);
+ json_object_boolean_true_add(json_path, "damped");
if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
- json_object_object_add(json_path, "bestpath", json_boolean_true);
+ json_object_boolean_true_add(json_path, "bestpath");
if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH))
- json_object_object_add(json_path, "multipath", json_boolean_true);
+ json_object_boolean_true_add(json_path, "multipath");
/* Internal route. */
if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as))
- json_object_object_add(json_path, "internal", json_boolean_true);
+ json_object_string_add(json_path, "path-from", "internal");
else
- json_object_object_add(json_path, "external", json_boolean_true);
+ json_object_string_add(json_path, "path-from", "external");
return;
}
@@ -6590,14 +6586,13 @@ route_vty_out (struct vty *vty, struct prefix *p,
json_object *json_paths)
{
struct attr *attr;
- json_object *json_path;
- json_object *json_int;
- json_object *json_string;
+ json_object *json_path = NULL;
+ json_object *json_nexthops = NULL;
+ json_object *json_nexthop_global = NULL;
+ json_object *json_nexthop_ll = NULL;
if (json_paths)
json_path = json_object_new_object();
- else
- json_path = NULL;
/* short status lead text */
route_vty_short_status_out (vty, binfo, json_path);
@@ -6622,16 +6617,15 @@ route_vty_out (struct vty *vty, struct prefix *p,
{
if (json_paths)
{
+ json_nexthop_global = json_object_new_object();
+
if (safi == SAFI_MPLS_VPN)
- {
- json_string = json_object_new_string(inet_ntoa (attr->extra->mp_nexthop_global_in));
- json_object_object_add(json_path, "nexthop-global", json_string);
- }
+ json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
else
- {
- json_string = json_object_new_string(inet_ntoa (attr->nexthop));
- json_object_object_add(json_path, "nexthop-global", json_string);
- }
+ json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop));
+
+ json_object_string_add(json_nexthop_global, "afi", "ipv4");
+ json_object_boolean_true_add(json_nexthop_global, "used");
}
else
{
@@ -6652,8 +6646,33 @@ route_vty_out (struct vty *vty, struct prefix *p,
if (json_paths)
{
- json_string = json_object_new_string(inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ));
- json_object_object_add(json_path, "nexthop-global", json_string);
+ json_nexthop_global = json_object_new_object();
+ json_object_string_add(json_nexthop_global, "ip",
+ inet_ntop (AF_INET6,
+ &attr->extra->mp_nexthop_global,
+ buf, BUFSIZ));
+ json_object_string_add(json_nexthop_global, "afi", "ipv6");
+ json_object_string_add(json_nexthop_global, "scope", "global");
+
+ /* We display both LL & GL if both have been received */
+ if ((attr->extra->mp_nexthop_len == 32) || (binfo->peer->conf_if))
+ {
+ json_nexthop_ll = json_object_new_object();
+ json_object_string_add(json_nexthop_ll, "ip",
+ inet_ntop (AF_INET6,
+ &attr->extra->mp_nexthop_local,
+ buf, BUFSIZ));
+ json_object_string_add(json_nexthop_ll, "afi", "ipv6");
+ json_object_string_add(json_nexthop_ll, "scope", "link-local");
+
+ if (IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global,
+ &attr->extra->mp_nexthop_local) != 0)
+ json_object_boolean_true_add(json_nexthop_ll, "used");
+ else
+ json_object_boolean_true_add(json_nexthop_global, "used");
+ }
+ else
+ json_object_boolean_true_add(json_nexthop_global, "used");
}
else
{
@@ -6672,10 +6691,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
/* MED/Metric */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
if (json_paths)
- {
- json_int = json_object_new_int(attr->med);
- json_object_object_add(json_path, "med", json_int);
- }
+ json_object_int_add(json_path, "med", attr->med);
else
vty_out (vty, "%10u", attr->med);
else
@@ -6685,10 +6701,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
/* Local Pref */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
if (json_paths)
- {
- json_int = json_object_new_int(attr->local_pref);
- json_object_object_add(json_path, "localpref", json_int);
- }
+ json_object_int_add(json_path, "localpref", attr->local_pref);
else
vty_out (vty, "%7u", attr->local_pref);
else
@@ -6698,11 +6711,9 @@ route_vty_out (struct vty *vty, struct prefix *p,
if (json_paths)
{
if (attr->extra)
- json_int = json_object_new_int(attr->extra->weight);
+ json_object_int_add(json_path, "weight", attr->extra->weight);
else
- json_int = json_object_new_int(0);
-
- json_object_object_add(json_path, "weight", json_int);
+ json_object_int_add(json_path, "weight", 0);
}
else
vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0));
@@ -6711,31 +6722,35 @@ route_vty_out (struct vty *vty, struct prefix *p,
if (attr->aspath)
{
if (json_paths)
- {
- if (!attr->aspath->str || !attr->aspath->segments)
- json_string = json_object_new_string("Local");
- else
- json_string = json_object_new_string(attr->aspath->str);
- json_object_object_add(json_path, "aspath", json_string);
- }
+ json_object_string_add(json_path, "aspath", attr->aspath->str);
else
- {
- aspath_print_vty (vty, "%s", attr->aspath, " ");
- }
+ aspath_print_vty (vty, "%s", attr->aspath, " ");
}
/* Print origin */
if (json_paths)
- {
- json_string = json_object_new_string(bgp_origin_str[attr->origin]);
- json_object_object_add(json_path, "origin", json_string);
- }
+ json_object_string_add(json_path, "origin", bgp_origin_long_str[attr->origin]);
else
vty_out (vty, "%s", bgp_origin_str[attr->origin]);
}
if (json_paths)
- json_object_array_add(json_paths, json_path);
+ {
+ if (json_nexthop_global || json_nexthop_ll)
+ {
+ json_nexthops = json_object_new_array();
+
+ if (json_nexthop_global)
+ json_object_array_add(json_nexthops, json_nexthop_global);
+
+ if (json_nexthop_ll)
+ json_object_array_add(json_nexthops, json_nexthop_ll);
+
+ json_object_object_add(json_path, "nexthops", json_nexthops);
+ }
+
+ json_object_array_add(json_paths, json_path);
+ }
else
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -6981,19 +6996,23 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
#ifdef HAVE_CLOCK_MONOTONIC
time_t tbuf;
#endif
- json_object *json_int;
- json_object *json_string;
- json_object *json_path = NULL;
- json_object *json_boolean_false;
- json_object *json_boolean_true = NULL;
+ json_object *json_bestpath = NULL;
json_object *json_cluster_list = NULL;
+ json_object *json_cluster_list_list = NULL;
+ json_object *json_ext_community = NULL;
+ json_object *json_last_update = NULL;
+ json_object *json_nexthop_global = NULL;
+ json_object *json_nexthop_ll = NULL;
+ json_object *json_nexthops = NULL;
+ json_object *json_path = NULL;
+ json_object *json_peer = NULL;
+ json_object *json_string = NULL;
if (json_paths)
{
json_path = json_object_new_object();
- json_boolean_false = json_object_new_boolean(0);
- json_boolean_true = json_object_new_boolean(1);
- json_cluster_list = json_object_new_array();
+ json_peer = json_object_new_object();
+ json_nexthop_global = json_object_new_object();
}
attr = binfo->attr;
@@ -7003,32 +7022,24 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line1 display AS-path, Aggregator */
if (attr->aspath)
{
- if (!json_paths)
- vty_out (vty, " ");
-
- if (!attr->aspath->segments)
- {
- if (json_paths)
- json_string = json_object_new_string("Local");
- else
- vty_out (vty, "Local");
- }
- else
+ if (json_paths)
+ {
+ json_object_lock(attr->aspath->json);
+ json_object_object_add(json_path, "aspath", attr->aspath->json);
+ }
+ else
{
- if (json_paths)
- json_string = json_object_new_string(attr->aspath->str);
+ if (attr->aspath->segments)
+ aspath_print_vty (vty, " %s", attr->aspath, "");
else
- aspath_print_vty (vty, "%s", attr->aspath, "");
+ vty_out (vty, " Local");
}
-
- if (json_paths)
- json_object_object_add(json_path, "aspath", json_string);
}
if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
{
if (json_paths)
- json_object_object_add(json_path, "removed", json_boolean_true);
+ json_object_boolean_true_add(json_path, "removed");
else
vty_out (vty, ", (removed)");
}
@@ -7036,7 +7047,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
{
if (json_paths)
- json_object_object_add(json_path, "stale", json_boolean_true);
+ json_object_boolean_true_add(json_path, "stale");
else
vty_out (vty, ", (stale)");
}
@@ -7045,10 +7056,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_int = json_object_new_int(attr->extra->aggregator_as);
- json_string = json_object_new_string(inet_ntoa (attr->extra->aggregator_addr));
- json_object_object_add(json_path, "aggregator-as", json_int);
- json_object_object_add(json_path, "aggregator-id", json_string);
+ json_object_int_add(json_path, "aggregator-as", attr->extra->aggregator_as);
+ json_object_string_add(json_path, "aggregator-id", inet_ntoa (attr->extra->aggregator_addr));
}
else
{
@@ -7061,7 +7070,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
{
if (json_paths)
- json_object_object_add(json_path, "rxed-from-rr-client", json_boolean_true);
+ json_object_boolean_true_add(json_path, "rxed-from-rr-client");
else
vty_out (vty, ", (Received from a RR-client)");
}
@@ -7069,7 +7078,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
{
if (json_paths)
- json_object_object_add(json_path, "rxed-from-rs-client", json_boolean_true);
+ json_object_boolean_true_add(json_path, "rxed-from-rs-client");
else
vty_out (vty, ", (Received from a RS-client)");
}
@@ -7077,14 +7086,14 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
{
if (json_paths)
- json_object_object_add(json_path, "dampening-history-entry", json_boolean_true);
+ json_object_boolean_true_add(json_path, "dampening-history-entry");
else
vty_out (vty, ", (history entry)");
}
else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
{
if (json_paths)
- json_object_object_add(json_path, "dampening-suppressed", json_boolean_true);
+ json_object_boolean_true_add(json_path, "dampening-suppressed");
else
vty_out (vty, ", (suppressed due to dampening)");
}
@@ -7093,26 +7102,27 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
vty_out (vty, "%s", VTY_NEWLINE);
/* Line2 display Next-hop, Neighbor, Router-id */
+ /* Display the nexthop */
if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
if (safi == SAFI_MPLS_VPN)
{
if (json_paths)
- json_string = json_object_new_string(inet_ntoa (attr->extra->mp_nexthop_global_in));
+ json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
else
vty_out (vty, " %s", inet_ntoa (attr->extra->mp_nexthop_global_in));
}
else
{
if (json_paths)
- json_string = json_object_new_string(inet_ntoa (attr->nexthop));
+ json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop));
else
vty_out (vty, " %s", inet_ntoa (attr->nexthop));
}
if (json_paths)
- json_object_object_add(json_path, "nexthop-global", json_string);
+ json_object_string_add(json_nexthop_global, "afi", "ipv4");
}
#ifdef HAVE_IPV6
else
@@ -7120,9 +7130,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
assert (attr->extra);
if (json_paths)
{
- json_string = json_object_new_string(inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
- buf, INET6_ADDRSTRLEN));
- json_object_object_add(json_path, "nexthop-global", json_string);
+ json_object_string_add(json_nexthop_global, "ip",
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+ buf, INET6_ADDRSTRLEN));
+ json_object_string_add(json_nexthop_global, "afi", "ipv6");
+ json_object_string_add(json_nexthop_global, "scope", "global");
}
else
{
@@ -7133,119 +7145,105 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
#endif /* HAVE_IPV6 */
- if (binfo->peer == bgp->peer_self)
- {
- if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ /* Display the IGP cost or 'inaccessible' */
+ if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
+ {
+ if (json_paths)
+ json_object_boolean_false_add(json_nexthop_global, "accessible");
+ else
+ vty_out (vty, " (inaccessible)");
+ }
+ else
+ {
+ if (binfo->extra && binfo->extra->igpmetric)
{
if (json_paths)
- json_string = json_object_new_string("0.0.0.0");
+ json_object_int_add(json_nexthop_global, "metric", binfo->extra->igpmetric);
else
- vty_out (vty, " from 0.0.0.0 ");
+ vty_out (vty, " (metric %u)", binfo->extra->igpmetric);
}
+
+ /* IGP cost is 0, display this only for json */
else
{
if (json_paths)
- json_string = json_object_new_string("::");
- else
- vty_out (vty, " from :: ");
+ json_object_int_add(json_nexthop_global, "metric", 0);
}
if (json_paths)
- {
- json_object_object_add(json_path, "peer-id", json_string);
- json_string = json_object_new_string(inet_ntoa(bgp->router_id));
- json_object_object_add(json_path, "peer-router-id", json_string);
- json_object_object_add(json_path, "nexthop-global-accessible",
- json_boolean_true);
- }
- else
- {
- vty_out (vty, "(%s)", inet_ntoa(bgp->router_id));
- }
- }
- else
+ json_object_boolean_true_add(json_nexthop_global, "accessible");
+ }
+
+ /* Display peer "from" output */
+ /* This path was originated locally */
+ if (binfo->peer == bgp->peer_self)
{
- if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
+
+ if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
{
if (json_paths)
- json_object_object_add(json_path, "nexthop-global-accessible", json_boolean_false);
+ json_object_string_add(json_peer, "peer-id", "0.0.0.0");
else
- vty_out (vty, " (inaccessible)");
+ vty_out (vty, " from 0.0.0.0 ");
}
- else if (binfo->extra && binfo->extra->igpmetric)
+ else
{
if (json_paths)
- {
- json_int = json_object_new_int(binfo->extra->igpmetric);
- json_object_object_add(json_path, "nexthop-global-igp-cost", json_int);
- json_object_object_add(json_path, "nexthop-global-accessible", json_boolean_true);
- }
+ json_object_string_add(json_peer, "peer-id", "::");
else
- {
- vty_out (vty, " (metric %u)", binfo->extra->igpmetric);
- }
+ vty_out (vty, " from :: ");
}
- /* IGP cost to nexthop is 0 */
+ if (json_paths)
+ json_object_string_add(json_peer, "router-id", inet_ntoa(bgp->router_id));
else
- if (json_paths)
- json_object_object_add(json_path, "nexthop-global-accessible", json_boolean_true);
+ vty_out (vty, "(%s)", inet_ntoa(bgp->router_id));
+ }
+
+ /* We RXed this path from one of our peers */
+ else
+ {
if (json_paths)
{
- json_string = json_object_new_string(sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
- json_object_object_add(json_path, "peer-id", json_string);
- if (binfo->peer->hostname)
- {
- json_string = json_object_new_string(binfo->peer->hostname);
- json_object_object_add(json_path, "peer-hostname", json_string);
- }
- if (binfo->peer->domainname)
- {
- json_string = json_object_new_string(binfo->peer->domainname);
- json_object_object_add(json_path, "peer-domainname", json_string);
- }
+ json_object_string_add(json_peer, "peer-id", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
+ json_object_string_add(json_peer, "router-id", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
+
+ if (binfo->peer->hostname)
+ json_object_string_add(json_peer, "hostname", binfo->peer->hostname);
+
+ if (binfo->peer->domainname)
+ json_object_string_add(json_peer, "domainname", binfo->peer->domainname);
+
if (binfo->peer->conf_if)
- {
- json_string = json_object_new_string(binfo->peer->conf_if);
- json_object_object_add(json_path, "peer-interface", json_string);
- }
+ json_object_string_add(json_peer, "interface", binfo->peer->conf_if);
}
else
{
if (binfo->peer->conf_if)
- {
- if (binfo->peer->hostname &&
- bgp_flag_check(binfo->peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
- vty_out (vty, " from %s(%s)", binfo->peer->hostname,
- binfo->peer->conf_if);
- else
- vty_out (vty, " from %s", binfo->peer->conf_if);
- }
+ {
+ if (binfo->peer->hostname &&
+ bgp_flag_check(binfo->peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
+ vty_out (vty, " from %s(%s)", binfo->peer->hostname,
+ binfo->peer->conf_if);
+ else
+ vty_out (vty, " from %s", binfo->peer->conf_if);
+ }
else
- {
- if (binfo->peer->hostname &&
- bgp_flag_check(binfo->peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
- vty_out (vty, " from %s(%s)", binfo->peer->hostname,
- binfo->peer->host);
- else
- vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
- }
-
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id));
- else
- vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
- }
+ {
+ if (binfo->peer->hostname &&
+ bgp_flag_check(binfo->peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
+ vty_out (vty, " from %s(%s)", binfo->peer->hostname,
+ binfo->peer->host);
+ else
+ vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN));
+ }
- /* Always encode the peer's router-id in the json output. We will
- * include the originator-id later if this is a reflected route.
- */
- if (json_paths)
- {
- json_string = json_object_new_string(inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
- json_object_object_add(json_path, "peer-router-id", json_string);
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id));
+ else
+ vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ));
}
}
@@ -7253,16 +7251,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
vty_out (vty, "%s", VTY_NEWLINE);
#ifdef HAVE_IPV6
- /* display nexthop local */
+ /* display the link-local nexthop */
if (attr->extra && attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
{
if (json_paths)
{
- json_string = json_object_new_string(inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
- buf, INET6_ADDRSTRLEN));
- json_object_object_add(json_path, "nexthop-local", json_string);
- json_object_object_add(json_path, "nexthop-local-accessible", json_boolean_true);
- json_object_object_add(json_path, "nexthop-local-used", json_boolean_true);
+ json_nexthop_ll = json_object_new_object();
+ json_object_string_add(json_nexthop_ll, "ip",
+ inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
+ buf, INET6_ADDRSTRLEN));
+ json_object_string_add(json_nexthop_ll, "afi", "ipv6");
+ json_object_string_add(json_nexthop_ll, "scope", "link-local");
+
+ json_object_boolean_true_add(json_nexthop_ll, "accessible");
+ json_object_boolean_true_add(json_nexthop_ll, "used");
}
else
{
@@ -7272,152 +7274,108 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
VTY_NEWLINE);
}
}
+ /* If we do not have a link-local nexthop then we must flag the global as "used" */
+ else
+ {
+ if (json_paths)
+ json_object_boolean_true_add(json_nexthop_global, "used");
+ }
#endif /* HAVE_IPV6 */
/* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */
if (json_paths)
- {
- json_string = json_object_new_string(bgp_origin_long_str[attr->origin]);
- json_object_object_add(json_path, "origin", json_string);
- }
+ json_object_string_add(json_path, "origin", bgp_origin_long_str[attr->origin]);
else
- {
- vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]);
- }
+ vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
{
if (json_paths)
- {
- json_int = json_object_new_int(attr->med);
- json_object_object_add(json_path, "med", json_int);
- }
+ json_object_int_add(json_path, "med", attr->med);
else
- {
- vty_out (vty, ", metric %u", attr->med);
- }
+ vty_out (vty, ", metric %u", attr->med);
}
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
{
if (json_paths)
- {
- json_int = json_object_new_int(attr->local_pref);
- json_object_object_add(json_path, "localpref", json_int);
- }
+ json_object_int_add(json_path, "localpref", attr->local_pref);
else
- {
- vty_out (vty, ", localpref %u", attr->local_pref);
- }
+ vty_out (vty, ", localpref %u", attr->local_pref);
}
else
{
if (json_paths)
- {
- json_int = json_object_new_int(bgp->default_local_pref);
- json_object_object_add(json_path, "localpref", json_int);
- }
+ json_object_int_add(json_path, "localpref", bgp->default_local_pref);
else
- {
- vty_out (vty, ", localpref %u", bgp->default_local_pref);
- }
+ vty_out (vty, ", localpref %u", bgp->default_local_pref);
}
if (attr->extra && attr->extra->weight != 0)
{
if (json_paths)
- {
- json_int = json_object_new_int(attr->extra->weight);
- json_object_object_add(json_path, "weight", json_int);
- }
+ json_object_int_add(json_path, "weight", attr->extra->weight);
else
- {
- vty_out (vty, ", weight %u", attr->extra->weight);
- }
+ vty_out (vty, ", weight %u", attr->extra->weight);
}
if (attr->extra && attr->extra->tag != 0)
{
if (json_paths)
- {
- json_int = json_object_new_int(attr->extra->tag);
- json_object_object_add(json_path, "tag", json_int);
- }
+ json_object_int_add(json_path, "tag", attr->extra->tag);
else
- {
- vty_out (vty, ", tag %d", attr->extra->tag);
- }
+ vty_out (vty, ", tag %d", attr->extra->tag);
}
if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
{
if (json_paths)
- json_object_object_add(json_path, "valid", json_boolean_false);
+ json_object_boolean_false_add(json_path, "valid");
else
vty_out (vty, ", invalid");
}
else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
{
if (json_paths)
- json_object_object_add(json_path, "valid", json_boolean_true);
+ json_object_boolean_true_add(json_path, "valid");
else
vty_out (vty, ", valid");
}
if (binfo->peer != bgp->peer_self)
{
- if (binfo->peer->as == binfo->peer->local_as)
+ if (binfo->peer->as == binfo->peer->local_as)
{
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
{
if (json_paths)
- {
- json_string = json_object_new_string("confed-internal");
- json_object_object_add(json_path, "peer-type", json_string);
- }
+ json_object_string_add(json_peer, "type", "confed-internal");
else
- {
- vty_out (vty, ", confed-internal");
- }
+ vty_out (vty, ", confed-internal");
}
else
{
if (json_paths)
- {
- json_string = json_object_new_string("internal");
- json_object_object_add(json_path, "peer-type", json_string);
- }
+ json_object_string_add(json_peer, "type", "internal");
else
- {
- vty_out (vty, ", internal");
- }
+ vty_out (vty, ", internal");
}
}
- else
+ else
{
if (bgp_confederation_peers_check(bgp, binfo->peer->as))
{
if (json_paths)
- {
- json_string = json_object_new_string("confed-external");
- json_object_object_add(json_path, "peer-type", json_string);
- }
+ json_object_string_add(json_peer, "type", "confed-external");
else
- {
- vty_out (vty, ", confed-external");
- }
+ vty_out (vty, ", confed-external");
}
else
{
if (json_paths)
- {
- json_string = json_object_new_string("external");
- json_object_object_add(json_path, "peer-type", json_string);
- }
+ json_object_string_add(json_peer, "type", "external");
else
- {
- vty_out (vty, ", external");
- }
+ vty_out (vty, ", external");
}
}
}
@@ -7425,8 +7383,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_object_object_add(json_path, "aggregated", json_boolean_true);
- json_object_object_add(json_path, "local", json_boolean_true);
+ json_object_boolean_true_add(json_path, "aggregated");
+ json_object_boolean_true_add(json_path, "local");
}
else
{
@@ -7436,7 +7394,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
else if (binfo->type != ZEBRA_ROUTE_BGP)
{
if (json_paths)
- json_object_object_add(json_path, "sourced", json_boolean_true);
+ json_object_boolean_true_add(json_path, "sourced");
else
vty_out (vty, ", sourced");
}
@@ -7444,8 +7402,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_object_object_add(json_path, "sourced", json_boolean_true);
- json_object_object_add(json_path, "local", json_boolean_true);
+ json_object_boolean_true_add(json_path, "sourced");
+ json_object_boolean_true_add(json_path, "local");
}
else
{
@@ -7456,7 +7414,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
{
if (json_paths)
- json_object_object_add(json_path, "atomic-aggregate", json_boolean_true);
+ json_object_boolean_true_add(json_path, "atomic-aggregate");
else
vty_out (vty, ", atomic-aggregate");
}
@@ -7466,7 +7424,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
bgp_info_mpath_count (binfo)))
{
if (json_paths)
- json_object_object_add(json_path, "multipath", json_boolean_true);
+ json_object_boolean_true_add(json_path, "multipath");
else
vty_out (vty, ", multipath");
}
@@ -7474,7 +7432,11 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
{
if (json_paths)
- json_object_object_add(json_path, "bestpath", json_boolean_true);
+ {
+ json_bestpath = json_object_new_object();
+ json_object_boolean_true_add(json_bestpath, "overall");
+ json_object_object_add(json_path, "bestpath", json_bestpath);
+ }
else
vty_out (vty, ", best");
}
@@ -7487,8 +7449,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_string = json_object_new_string(attr->community->str);
- json_object_object_add(json_path, "community", json_string);
+ json_object_lock(attr->community->json);
+ json_object_object_add(json_path, "community", attr->community->json);
}
else
{
@@ -7502,8 +7464,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_string = json_object_new_string(attr->extra->ecommunity->str);
- json_object_object_add(json_path, "extended-community", json_string);
+ json_ext_community = json_object_new_object();
+ json_object_string_add(json_ext_community, "string", attr->extra->ecommunity->str);
+ json_object_object_add(json_path, "extended-community", json_ext_community);
}
else
{
@@ -7520,15 +7483,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
{
if (json_paths)
- {
- json_string = json_object_new_string(inet_ntoa (attr->extra->originator_id));
- json_object_object_add(json_path, "originator-id", json_string);
- }
+ json_object_string_add(json_path, "originator-id", inet_ntoa (attr->extra->originator_id));
else
- {
- vty_out (vty, " Originator: %s",
- inet_ntoa (attr->extra->originator_id));
- }
+ vty_out (vty, " Originator: %s",
+ inet_ntoa (attr->extra->originator_id));
}
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
@@ -7537,11 +7495,21 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (json_paths)
{
+ json_cluster_list = json_object_new_object();
+ json_cluster_list_list = json_object_new_array();
+
for (i = 0; i < attr->extra->cluster->length / 4; i++)
{
json_string = json_object_new_string(inet_ntoa (attr->extra->cluster->list[i]));
- json_object_array_add(json_cluster_list, json_string);
+ json_object_array_add(json_cluster_list_list, json_string);
}
+
+ /* struct cluster_list does not have "str" variable like
+ * aspath and community do. Add this someday if someone
+ * asks for it.
+ json_object_string_add(json_cluster_list, "string", attr->extra->cluster->str);
+ */
+ json_object_object_add(json_cluster_list, "list", json_cluster_list_list);
json_object_object_add(json_path, "cluster-list", json_cluster_list);
}
else
@@ -7568,11 +7536,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
{
if (json_paths)
{
- json_int = json_object_new_int(binfo->addpath_rx_id);
- json_object_object_add(json_path, "addpath-rx-id", json_int);
-
- json_int = json_object_new_int(binfo->addpath_tx_id);
- json_object_object_add(json_path, "addpath-tx-id", json_int);
+ json_object_int_add(json_path, "addpath-rx-id", binfo->addpath_rx_id);
+ json_object_int_add(json_path, "addpath-tx-id", binfo->addpath_tx_id);
}
else
{
@@ -7586,24 +7551,48 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
if (json_paths)
- json_string = json_object_new_string(ctime(&tbuf));
+ {
+ json_last_update = json_object_new_object();
+ json_object_int_add(json_last_update, "epoch", tbuf);
+ json_object_string_add(json_last_update, "string", ctime(&tbuf));
+ json_object_object_add(json_path, "last-update", json_last_update);
+ }
else
vty_out (vty, " Last update: %s", ctime(&tbuf));
#else
if (json_paths)
- json_string = json_object_new_string(ctime(&binfo->uptime));
+ {
+ json_last_update = json_object_new_object();
+ json_object_int_add(json_last_update, "epoch", tbuf);
+ json_object_string_add(json_last_update, "string", ctime(&binfo->uptime));
+ json_object_object_add(json_path, "last-update", json_last_update);
+ }
else
vty_out (vty, " Last update: %s", ctime(&binfo->uptime));
#endif /* HAVE_CLOCK_MONOTONIC */
- if (json_paths)
- json_object_object_add(json_path, "last-update", json_string);
}
/* We've constructed the json object for this path, add it to the json
* array of paths
*/
if (json_paths)
- json_object_array_add(json_paths, json_path);
+ {
+ if (json_nexthop_global || json_nexthop_ll)
+ {
+ json_nexthops = json_object_new_array();
+
+ if (json_nexthop_global)
+ json_object_array_add(json_nexthops, json_nexthop_global);
+
+ if (json_nexthop_ll)
+ json_object_array_add(json_nexthops, json_nexthop_ll);
+
+ json_object_object_add(json_path, "nexthops", json_nexthops);
+ }
+
+ json_object_object_add(json_path, "peer", json_peer);
+ json_object_array_add(json_paths, json_path);
+ }
else
vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -7653,21 +7642,15 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
struct prefix *p;
char buf[BUFSIZ];
char buf2[BUFSIZ];
- json_object *json;
- json_object *json_int;
- json_object *json_paths;
- json_object *json_routes;
- json_object *json_string;
+ json_object *json = NULL;
+ json_object *json_paths = NULL;
+ json_object *json_routes = NULL;
if (use_json)
{
json = json_object_new_object();
- json_int = json_object_new_int(table->version);
- json_object_object_add(json, "table-version", json_int);
-
- json_string = json_object_new_string(inet_ntoa (*router_id));
- json_object_object_add(json, "router-id", json_string);
-
+ json_object_int_add(json, "table-version", table->version);
+ json_object_string_add(json, "router-id", inet_ntoa (*router_id));
json_routes = json_object_new_object();
}
@@ -7889,9 +7872,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
{
json_object_object_add(json, "routes", json_routes);
vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
-
- // Recursively free all json structures
- json_object_put(json);
+ json_object_free(json);
}
else
{
@@ -7951,20 +7932,15 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
int no_advertise = 0;
int local_as = 0;
int first = 0;
- json_object *json_string;
- json_object *json_int;
json_object *json_adv_to = NULL;
+ json_object *json_peer = NULL;
p = &rn->p;
if (json)
{
- json_string = json_object_new_string(inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN));
- json_object_object_add(json, "prefix", json_string);
-
- json_int = json_object_new_int(p->prefixlen);
- json_object_object_add(json, "prefixlen", json_int);
- json_adv_to = json_object_new_array();
+ json_object_string_add(json, "prefix", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN));
+ json_object_int_add(json, "prefixlen", p->prefixlen);
}
else
{
@@ -8027,23 +8003,24 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
{
if (json)
{
+ /* 'advertised-to' is a dictionary of peers we have advertised this
+ * prefix too. The key is the peer's IP or swpX, the value is the
+ * hostname if we know it and "" if not.
+ */
+ json_peer = json_object_new_object();
+
if (peer->hostname)
- {
- json_string = json_object_new_string(peer->hostname);
- json_object_array_add(json_adv_to, json_string);
+ json_object_string_add(json_peer, "hostname", peer->hostname);
+
+ if (!json_adv_to)
+ json_adv_to = json_object_new_object();
- /* TODO: Have to add domain name here too */
- }
if (peer->conf_if)
- {
- json_string = json_object_new_string(peer->conf_if);
- json_object_array_add(json_adv_to, json_string);
- }
+ json_object_object_add(json_adv_to, peer->conf_if, json_peer);
else
- {
- json_string = json_object_new_string(sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
- json_object_array_add(json_adv_to, json_string);
- }
+ json_object_object_add(json_adv_to,
+ sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN),
+ json_peer);
}
else
{
@@ -8101,8 +8078,8 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
struct bgp_node *rm;
struct bgp_info *ri;
struct bgp_table *table;
- json_object *json;
- json_object *json_paths;
+ json_object *json = NULL;
+ json_object *json_paths = NULL;
/* Check IP address argument. */
ret = str2prefix (ip_str, &match);
@@ -8119,11 +8096,6 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
json = json_object_new_object();
json_paths = json_object_new_array();
}
- else
- {
- json = NULL;
- json_paths = NULL;
- }
if (safi == SAFI_MPLS_VPN)
{
@@ -8202,9 +8174,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
json_object_object_add(json, "paths", json_paths);
vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
-
- // Recursively free all json structures
- json_object_put(json);
+ json_object_free(json);
}
else
{
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 124ac4ea1d..865a24d3ff 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -21,7 +21,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ROUTE_H
#define _QUAGGA_BGP_ROUTE_H
-#include <json/json.h>
+#include "lib/json.h"
#include "queue.h"
#include "bgp_table.h"
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e46dfa705b..71c9ba1b94 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -8453,11 +8453,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
char timebuf[BGP_UPTIME_LEN], dn_flag[2];
int len;
json_object *json = NULL;
- json_object *json_int = NULL;
- json_object *json_string = NULL;
json_object *json_peer = NULL;
json_object *json_peers = NULL;
- json_object *json_boolean_true = NULL;
/* Header string for each address family. */
static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd";
@@ -8465,8 +8462,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
if (use_json)
{
json = json_object_new_object();
- json_peers = json_object_new_array();
- json_boolean_true = json_object_new_boolean(1);
+ json_peers = json_object_new_object();
}
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
@@ -8484,11 +8480,8 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
/* Usage summary and header */
if (use_json)
{
- json_string = json_object_new_string(inet_ntoa (bgp->router_id));
- json_object_object_add(json, "router-id", json_string);
-
- json_int = json_object_new_int(bgp->as);
- json_object_object_add(json, "as", json_int);
+ json_object_string_add(json, "router-id", inet_ntoa (bgp->router_id));
+ json_object_int_add(json, "as", bgp->as);
}
else
{
@@ -8501,36 +8494,28 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
{
if (use_json)
{
- json_int = json_object_new_int(bgp->v_update_delay);
- json_object_object_add(json, "update-delay-limit", json_int);
+ json_object_int_add(json, "update-delay-limit", bgp->v_update_delay);
if (bgp->v_update_delay != bgp->v_establish_wait)
- {
- json_int = json_object_new_int(bgp->v_establish_wait);
- json_object_object_add(json, "update-delay-establish-wait", json_int);
- }
+ json_object_int_add(json, "update-delay-establish-wait", bgp->v_establish_wait);
if (bgp_update_delay_active(bgp))
{
- json_string = json_object_new_string(bgp->update_delay_begin_time);
- json_object_object_add(json, "update-delay-first-neighbor", json_string);
- json_object_object_add(json, "update-delay-in-progress", json_boolean_true);
+ json_object_string_add(json, "update-delay-first-neighbor", bgp->update_delay_begin_time);
+ json_object_boolean_true_add(json, "update-delay-in-progress");
}
else
{
if (bgp->update_delay_over)
{
- json_string = json_object_new_string(bgp->update_delay_begin_time);
- json_object_object_add(json, "update-delay-first-neighbor", json_string);
-
- json_string = json_object_new_string(bgp->update_delay_end_time);
- json_object_object_add(json, "update-delay-bestpath-resumed", json_string);
-
- json_string = json_object_new_string(bgp->update_delay_zebra_resume_time);
- json_object_object_add(json, "update-delay-zebra-update-resume", json_string);
-
- json_string = json_object_new_string(bgp->update_delay_peers_resume_time);
- json_object_object_add(json, "update-delay-peer-update-resume", json_string);
+ json_object_string_add(json, "update-delay-first-neighbor",
+ bgp->update_delay_begin_time);
+ json_object_string_add(json, "update-delay-bestpath-resumed",
+ bgp->update_delay_end_time);
+ json_object_string_add(json, "update-delay-zebra-update-resume",
+ bgp->update_delay_zebra_resume_time);
+ json_object_string_add(json, "update-delay-peer-update-resume",
+ bgp->update_delay_peers_resume_time);
}
}
}
@@ -8568,43 +8553,34 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
if (use_json)
{
if (bgp_maxmed_onstartup_configured(bgp) && bgp->maxmed_active)
- json_object_object_add(json, "max-med-on-startup", json_boolean_true);
+ json_object_boolean_true_add(json, "max-med-on-startup");
if (bgp->v_maxmed_admin)
- json_object_object_add(json, "max-med-administrative", json_boolean_true);
+ json_object_boolean_true_add(json, "max-med-administrative");
- json_int = json_object_new_int(bgp_table_version(bgp->rib[afi][safi]));
- json_object_object_add(json, "table-version", json_int);
+ json_object_int_add(json, "table-version", bgp_table_version(bgp->rib[afi][safi]));
ents = bgp_table_count (bgp->rib[afi][safi]);
- json_int = json_object_new_int(ents);
- json_object_object_add(json, "rib-count", json_int);
- json_int = json_object_new_int(ents * sizeof (struct bgp_node));
- json_object_object_add(json, "rib-memory", json_int);
+ json_object_int_add(json, "rib-count", ents);
+ json_object_int_add(json, "rib-memory", ents * sizeof (struct bgp_node));
ents = listcount (bgp->peer);
- json_int = json_object_new_int(ents);
- json_object_object_add(json, "peer-count", json_int);
- json_int = json_object_new_int(ents * sizeof (struct peer));
- json_object_object_add(json, "peer-memory", json_int);
+ json_object_int_add(json, "peer-count", ents);
+ json_object_int_add(json, "peer-memory", ents * sizeof (struct peer));
if ((ents = listcount (bgp->rsclient)))
{
- json_int = json_object_new_int(ents);
- json_object_object_add(json, "rsclient-count", json_int);
- json_int = json_object_new_int(ents * sizeof (struct peer));
- json_object_object_add(json, "rsclient-memory", json_int);
+ json_object_int_add(json, "rsclient-count", ents);
+ json_object_int_add(json, "rsclient-memory", ents * sizeof (struct peer));
}
if ((ents = listcount (bgp->group)))
{
- json_int = json_object_new_int(ents);
- json_object_object_add(json, "peer-group-count", json_int);
- json_int = json_object_new_int(ents * sizeof (struct peer_group));
- json_object_object_add(json, "peer-group-memory", json_int);
+ json_object_int_add(json, "peer-group-count", ents);
+ json_object_int_add(json, "peer-group-memory", ents * sizeof (struct peer_group));
}
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
- json_object_object_add(json, "dampening-enabled", json_boolean_true);
+ json_object_boolean_true_add(json, "dampening-enabled");
}
else
{
@@ -8657,69 +8633,48 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
json_peer = json_object_new_object();
if (peer_dynamic_neighbor(peer))
- json_object_object_add(json_peer, "dynamic-peer", json_boolean_true);
-
- json_string = json_object_new_string(peer->host);
- json_object_object_add(json_peer, "peer-id", json_string);
+ json_object_boolean_true_add(json_peer, "dynamic-peer");
if (peer->hostname)
- {
- json_string = json_object_new_string(peer->hostname);
- json_object_object_add(json_peer, "hostname", json_string);
- }
+ json_object_string_add(json_peer, "hostname", peer->hostname);
if (peer->domainname)
- {
- json_string = json_object_new_string(peer->domainname);
- json_object_object_add(json_peer, "domainname", json_string);
- }
-
- json_int = json_object_new_int(peer->as);
- json_object_object_add(json_peer, "remote-as", json_int);
-
- json_int = json_object_new_int(4);
- json_object_object_add(json_peer, "version", json_int);
-
- json_int = json_object_new_int(peer->open_in + peer->update_in + peer->keepalive_in
- + peer->notify_in + peer->refresh_in
- + peer->dynamic_cap_in);
- json_object_object_add(json_peer, "msgrcvd", json_int);
-
- json_int = json_object_new_int(peer->open_out + peer->update_out + peer->keepalive_out
- + peer->notify_out + peer->refresh_out
- + peer->dynamic_cap_out);
- json_object_object_add(json_peer, "msgsent", json_int);
-
- json_int = json_object_new_int(peer->version[afi][safi]);
- json_object_object_add(json_peer, "table-version", json_int);
-
- json_int = json_object_new_int(peer->obuf->count);
- json_object_object_add(json_peer, "outq", json_int);
-
- json_int = json_object_new_int(0);
- json_object_object_add(json_peer, "inq", json_int);
-
- json_string = json_object_new_string(peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
- json_object_object_add(json_peer, "uptime", json_string);
-
- json_int = json_object_new_int(peer->pcount[afi][safi]);
- json_object_object_add(json_peer, "prefix-received-count", json_int);
-
- json_int = json_object_new_int(bgp_adj_out_count(peer, afi, safi));
- json_object_object_add(json_peer, "prefix-advertised-count", json_int);
+ json_object_string_add(json_peer, "domainname", peer->domainname);
+
+ json_object_int_add(json_peer, "remote-as", peer->as);
+ json_object_int_add(json_peer, "version", 4);
+ json_object_int_add(json_peer, "msgrcvd",
+ peer->open_in + peer->update_in + peer->keepalive_in
+ + peer->notify_in + peer->refresh_in
+ + peer->dynamic_cap_in);
+ json_object_int_add(json_peer, "msgsent",
+ peer->open_out + peer->update_out + peer->keepalive_out
+ + peer->notify_out + peer->refresh_out
+ + peer->dynamic_cap_out);
+
+ json_object_int_add(json_peer, "table-version", peer->version[afi][safi]);
+ json_object_int_add(json_peer, "outq", peer->obuf->count);
+ json_object_int_add(json_peer, "inq", 0);
+ json_object_string_add(json_peer, "uptime",
+ peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
+ json_object_int_add(json_peer, "prefix-received-count", peer->pcount[afi][safi]);
+ json_object_int_add(json_peer, "prefix-advertised-count", bgp_adj_out_count(peer, afi, safi));
if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- json_string = json_object_new_string("Idle (Admin)");
-
+ json_object_string_add(json_peer, "state", "Idle (Admin)");
else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- json_string = json_object_new_string("Idle (PfxCt)");
-
+ json_object_string_add(json_peer, "state", "Idle (PfxCt)");
else
- json_string = json_object_new_string(LOOKUP(bgp_status_msg, peer->status));
+ json_object_string_add(json_peer, "state", LOOKUP(bgp_status_msg, peer->status));
- json_object_object_add(json_peer, "state", json_string);
+ if (peer->conf_if)
+ json_object_string_add(json_peer, "id-type", "interface");
+ else if (peer->su.sa.sa_family == AF_INET)
+ json_object_string_add(json_peer, "id-type", "ipv4");
+ else if (peer->su.sa.sa_family == AF_INET6)
+ json_object_string_add(json_peer, "id-type", "ipv6");
- json_object_array_add(json_peers, json_peer);
+ json_object_object_add(json_peers, peer->host, json_peer);
}
else
{
@@ -8756,7 +8711,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
0,
peer->obuf->count);
- vty_out (vty, "%8s",
+ vty_out (vty, "%-8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
if (peer->status == Established)
@@ -8779,16 +8734,11 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi,
{
json_object_object_add(json, "peers", json_peers);
- json_int = json_object_new_int(count);
- json_object_object_add(json, "total-peers", json_int);
-
- json_int = json_object_new_int(dn_count);
- json_object_object_add(json, "dynamic-peers", json_int);
+ json_object_int_add(json, "total-peers", count);
+ json_object_int_add(json, "dynamic-peers", dn_count);
vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE);
-
- // Recursively free all json structures
- json_object_put(json);
+ json_object_free(json);
}
else
{
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index ee7b046202..ba23f18dd1 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -5818,7 +5818,7 @@ peer_uptime (time_t uptime2, char *buf, size_t len)
/* If there is no connection has been done before print `never'. */
if (uptime2 == 0)
{
- snprintf (buf, len, "never ");
+ snprintf (buf, len, "never");
return buf;
}
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f64972dd0d..d32ac1f7ab 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,7 +12,7 @@ libzebra_la_SOURCES = \
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
- sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c
+ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c json.c
BUILT_SOURCES = memtypes.h route_types.h gitversion.h
@@ -27,7 +27,7 @@ pkginclude_HEADERS = \
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
- workqueue.h route_types.h libospf.h nexthop.h
+ workqueue.h route_types.h libospf.h nexthop.h json.h
EXTRA_DIST = \
regex.c regex-gnu.h \
diff --git a/lib/json.c b/lib/json.c
new file mode 100644
index 0000000000..07b70e4f06
--- /dev/null
+++ b/lib/json.c
@@ -0,0 +1,59 @@
+/* json-c wrapper
+ * Copyright (C) 2015 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "lib/json.h"
+
+void
+json_object_string_add(struct json_object* obj, const char *key,
+ const char *s)
+{
+ json_object_object_add(obj, key, json_object_new_string(s));
+}
+
+void
+json_object_int_add(struct json_object* obj, const char *key, int32_t i)
+{
+ json_object_object_add(obj, key, json_object_new_int(i));
+}
+
+void
+json_object_boolean_false_add(struct json_object* obj, const char *key)
+{
+ json_object_object_add(obj, key, json_object_new_boolean(0));
+}
+
+void
+json_object_boolean_true_add(struct json_object* obj, const char *key)
+{
+ json_object_object_add(obj, key, json_object_new_boolean(1));
+}
+
+struct json_object*
+json_object_lock(struct json_object *obj)
+{
+ return json_object_get(obj);
+}
+
+void
+json_object_free(struct json_object *obj)
+{
+ json_object_put(obj);
+}
diff --git a/lib/json.h b/lib/json.h
new file mode 100644
index 0000000000..e9b1976b96
--- /dev/null
+++ b/lib/json.h
@@ -0,0 +1,38 @@
+/* json-c wrapper
+ * Copyright (C) 2015 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_JSON_H
+#define _QUAGGA_JSON_H
+
+#include <json/json.h>
+
+extern void json_object_string_add(struct json_object* obj, const char *key,
+ const char *s);
+extern void json_object_int_add(struct json_object* obj, const char *key,
+ int32_t i);
+extern void json_object_boolean_false_add(struct json_object* obj,
+ const char *key);
+extern void json_object_boolean_true_add(struct json_object* obj,
+ const char *key);
+extern struct json_object* json_object_lock(struct json_object *obj);
+extern void json_object_free(struct json_object *obj);
+
+#endif /* _QUAGGA_JSON_H */