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 #include -#include #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 +#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 - /* 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 -#include #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_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("Local"); + if (attr->aspath->segments) + aspath_print_vty (vty, " %s", attr->aspath, ""); else - vty_out (vty, "Local"); + vty_out (vty, " Local"); } - else - { - if (json_paths) - json_string = json_object_new_string(attr->aspath->str); - else - aspath_print_vty (vty, "%s", attr->aspath, ""); - } - - 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 */ + + /* 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_object_int_add(json_nexthop_global, "metric", binfo->extra->igpmetric); + else + vty_out (vty, " (metric %u)", binfo->extra->igpmetric); + } + + /* IGP cost is 0, display this only for json */ + else + { + if (json_paths) + json_object_int_add(json_nexthop_global, "metric", 0); + } + + if (json_paths) + 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 (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { if (json_paths) - json_string = json_object_new_string("0.0.0.0"); + json_object_string_add(json_peer, "peer-id", "0.0.0.0"); else vty_out (vty, " from 0.0.0.0 "); } else { if (json_paths) - json_string = json_object_new_string("::"); + json_object_string_add(json_peer, "peer-id", "::"); else vty_out (vty, " from :: "); } 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); - } + json_object_string_add(json_peer, "router-id", inet_ntoa(bgp->router_id)); else - { - vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); - } + vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); } + + /* We RXed this path from one of our peers */ else { - if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) - { - if (json_paths) - json_object_object_add(json_path, "nexthop-global-accessible", json_boolean_false); - else - vty_out (vty, " (inaccessible)"); - } - else if (binfo->extra && binfo->extra->igpmetric) - { - 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); - } - else - { - vty_out (vty, " (metric %u)", binfo->extra->igpmetric); - } - } - - /* IGP cost to nexthop is 0 */ - else - if (json_paths) - json_object_object_add(json_path, "nexthop-global-accessible", json_boolean_true); 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 (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)); - } - - /* 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) { - if (peer->hostname) - { - json_string = json_object_new_string(peer->hostname); - json_object_array_add(json_adv_to, json_string); + /* '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_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 +#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_object_string_add(json_peer, "domainname", peer->domainname); - json_int = json_object_new_int(peer->as); - json_object_object_add(json_peer, "remote-as", json_int); + 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_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_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 + +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 */