From d33fc23bf8d70bea0fabae541e127b4bdbc77a8d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 7 Mar 2018 18:54:09 +0100 Subject: [PATCH] bgpd: support for json in show bgp ipv4 flowspec commands The json format is returd when requested from the two commands: - show bgp ipv4 flowspec - show bgp ipv4 flowspec detail Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 2 +- bgpd/bgp_flowspec.c | 2 +- bgpd/bgp_flowspec.h | 11 ++-- bgpd/bgp_flowspec_util.h | 3 +- bgpd/bgp_flowspec_vty.c | 108 +++++++++++++++++++++++++++++++-------- bgpd/bgp_route.c | 9 ++-- 6 files changed, 105 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 8801028313..ae4ff5d67e 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2223,7 +2223,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr, fs->prefix.prefixlen, return_string, - NLRI_STRING_FORMAT_DEBUG); + NLRI_STRING_FORMAT_DEBUG, NULL); snprintf(str, size, "FS %s Match{%s}", afi2str(afi), return_string); } else diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index d53271e851..5db7e37089 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -156,7 +156,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, p.u.prefix_flowspec.ptr, p.u.prefix_flowspec.prefixlen, return_string, - NLRI_STRING_FORMAT_MIN); + NLRI_STRING_FORMAT_MIN, NULL); snprintf(ec_string, BGP_FLOWSPEC_NLRI_STRING_MAX, "EC{none}"); if (attr && attr->ecommunity) { diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index 791ed2e693..392b321530 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -19,9 +19,11 @@ #ifndef _FRR_BGP_FLOWSPEC_H #define _FRR_BGP_FLOWSPEC_H -#define NLRI_STRING_FORMAT_LARGE 0 -#define NLRI_STRING_FORMAT_DEBUG 1 -#define NLRI_STRING_FORMAT_MIN 2 +#define NLRI_STRING_FORMAT_LARGE 0 +#define NLRI_STRING_FORMAT_DEBUG 1 +#define NLRI_STRING_FORMAT_MIN 2 +#define NLRI_STRING_FORMAT_JSON 3 +#define NLRI_STRING_FORMAT_JSON_SIMPLE 4 #define BGP_FLOWSPEC_NLRI_STRING_MAX 512 @@ -39,7 +41,8 @@ extern int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, unsigned long *total_cum); extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, - char *return_string, int format); + char *return_string, int format, + json_object *json_path); extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct bgp_info *binfo, diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 55a464a718..5d262dbbc7 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -26,7 +26,8 @@ enum bgp_flowspec_util_nlri_t { BGP_FLOWSPEC_VALIDATE_ONLY = 0, BGP_FLOWSPEC_RETURN_STRING = 1, - BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2 + BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2, + BGP_FLOWSPEC_RETURN_JSON = 3, }; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 76ac0888b4..eae9bedcbd 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -79,7 +79,8 @@ static const struct message bgp_flowspec_display_min[] = { /* Parse FLOWSPEC NLRI*/ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, - char *return_string, int format) + char *return_string, int format, + json_object *json_path) { uint32_t offset = 0; int type; @@ -90,6 +91,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char extra[2] = ""; char pre_extra[2] = ""; const struct message *bgp_flowspec_display; + enum bgp_flowspec_util_nlri_t type_util; if (format == NLRI_STRING_FORMAT_LARGE) { snprintf(pre_extra, sizeof(pre_extra), "\t"); @@ -97,6 +99,8 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, bgp_flowspec_display = bgp_flowspec_display_large; } else bgp_flowspec_display = bgp_flowspec_display_min; + /* if needed. type_util can be set to other values */ + type_util = BGP_FLOWSPEC_RETURN_STRING; error = 0; while (offset < len-1 && error >= 0) { type = nlri_content[offset]; @@ -105,12 +109,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_DEST_PREFIX: case FLOWSPEC_SRC_PREFIX: ret = bgp_flowspec_ip_address( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, type, ""), @@ -122,12 +132,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_SRC_PORT: case FLOWSPEC_ICMP_TYPE: case FLOWSPEC_ICMP_CODE: - ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_RETURN_STRING, + ret = bgp_flowspec_op_decode(type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -136,12 +152,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, break; case FLOWSPEC_TCP_FLAGS: ret = bgp_flowspec_tcpflags_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, type, ""), @@ -150,12 +172,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_PKT_LEN: case FLOWSPEC_DSCP: ret = bgp_flowspec_op_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content + offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -164,12 +192,19 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, break; case FLOWSPEC_FRAGMENT: ret = bgp_flowspec_fragment_type_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content + offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -191,11 +226,21 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct attr *attr; char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; char *s; + json_object *json_nlri_path = NULL; + json_object *json_ecom_path = NULL; + json_object *json_time_path = NULL; + char timebuf[BGP_UPTIME_LEN]; /* Print prefix */ if (p != NULL) { if (p->family != AF_FLOWSPEC) return; + if (json_paths) { + if (display == NLRI_STRING_FORMAT_JSON) + json_nlri_path = json_object_new_object(); + else + json_nlri_path = json_paths; + } if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n", binfo->flags); @@ -203,13 +248,16 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, p->u.prefix_flowspec.ptr, p->u.prefix_flowspec.prefixlen, return_string, - display); + display, + json_nlri_path); if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "%s", return_string); else if (display == NLRI_STRING_FORMAT_DEBUG) vty_out(vty, "%s", return_string); - else + else if (display == NLRI_STRING_FORMAT_MIN) vty_out(vty, " %-30s", return_string); + else if (json_paths && display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, json_nlri_path); } if (!binfo) return; @@ -222,16 +270,27 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, return; if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "\t%s\n", s); - else + else if (display == NLRI_STRING_FORMAT_MIN) vty_out(vty, "%s", s); + else if (json_paths) { + json_ecom_path = json_object_new_object(); + json_object_string_add(json_ecom_path, + "ecomlist", s); + if (display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, + json_ecom_path); + } XFREE(MTYPE_ECOMMUNITY_STR, s); } - if (display == NLRI_STRING_FORMAT_LARGE) { - char timebuf[BGP_UPTIME_LEN]; - - vty_out(vty, "\tup for %8s\n", - peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, - 0, NULL)); + peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL); + if (display == NLRI_STRING_FORMAT_LARGE) + vty_out(vty, "\tup for %8s\n", timebuf); + else if (json_paths) { + json_time_path = json_object_new_object(); + json_object_string_add(json_time_path, + "time", timebuf); + if (display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, json_time_path); } } @@ -246,17 +305,18 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, struct bgp_node *rn; unsigned long total_count = 0; json_object *json_paths = NULL; - int display; + int display = NLRI_STRING_FORMAT_LARGE; if (type != bgp_show_type_detail) return CMD_SUCCESS; - display = NLRI_STRING_FORMAT_LARGE; - if (use_json) /* XXX */ - return CMD_SUCCESS; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { if (rn->info == NULL) continue; + if (use_json) { + json_paths = json_object_new_array(); + display = NLRI_STRING_FORMAT_JSON; + } for (ri = rn->info; ri; ri = ri->next) { total_count++; route_vty_out_flowspec(vty, &rn->p, @@ -264,8 +324,16 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, json_paths); } + if (use_json) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_paths, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json_paths); + json_paths = NULL; + } } - if (total_count) + if (total_count && !use_json) vty_out(vty, "\nDisplayed %ld flowspec entries\n", total_count); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index db82386e72..ad3d57a9ae 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6319,7 +6319,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, #endif } else if (p->family == AF_FLOWSPEC) { route_vty_out_flowspec(vty, p, NULL, - NLRI_STRING_FORMAT_MIN, json); + json ? + NLRI_STRING_FORMAT_JSON_SIMPLE : + NLRI_STRING_FORMAT_MIN, json); } else { if (!json) len = vty_out( @@ -6511,9 +6513,10 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, "used"); } else vty_out(vty, "%-16s", inet_ntoa(attr->nexthop)); - } + } else if (safi == SAFI_FLOWSPEC) { + /* already done */ /* IPv4 Next Hop */ - else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { + } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { if (json_paths) { json_nexthop_global = json_object_new_object();