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 <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2018-03-07 18:54:09 +01:00
parent e7d78d0f2c
commit d33fc23bf8
6 changed files with 105 additions and 30 deletions

View File

@ -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, bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr,
fs->prefix.prefixlen, fs->prefix.prefixlen,
return_string, return_string,
NLRI_STRING_FORMAT_DEBUG); NLRI_STRING_FORMAT_DEBUG, NULL);
snprintf(str, size, "FS %s Match{%s}", afi2str(afi), snprintf(str, size, "FS %s Match{%s}", afi2str(afi),
return_string); return_string);
} else } else

View File

@ -156,7 +156,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
p.u.prefix_flowspec.ptr, p.u.prefix_flowspec.ptr,
p.u.prefix_flowspec.prefixlen, p.u.prefix_flowspec.prefixlen,
return_string, return_string,
NLRI_STRING_FORMAT_MIN); NLRI_STRING_FORMAT_MIN, NULL);
snprintf(ec_string, BGP_FLOWSPEC_NLRI_STRING_MAX, snprintf(ec_string, BGP_FLOWSPEC_NLRI_STRING_MAX,
"EC{none}"); "EC{none}");
if (attr && attr->ecommunity) { if (attr && attr->ecommunity) {

View File

@ -22,6 +22,8 @@
#define NLRI_STRING_FORMAT_LARGE 0 #define NLRI_STRING_FORMAT_LARGE 0
#define NLRI_STRING_FORMAT_DEBUG 1 #define NLRI_STRING_FORMAT_DEBUG 1
#define NLRI_STRING_FORMAT_MIN 2 #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 #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); unsigned long *total_cum);
extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, 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, extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
struct bgp_info *binfo, struct bgp_info *binfo,

View File

@ -26,7 +26,8 @@
enum bgp_flowspec_util_nlri_t { enum bgp_flowspec_util_nlri_t {
BGP_FLOWSPEC_VALIDATE_ONLY = 0, BGP_FLOWSPEC_VALIDATE_ONLY = 0,
BGP_FLOWSPEC_RETURN_STRING = 1, BGP_FLOWSPEC_RETURN_STRING = 1,
BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2,
BGP_FLOWSPEC_RETURN_JSON = 3,
}; };

View File

@ -79,7 +79,8 @@ static const struct message bgp_flowspec_display_min[] = {
/* Parse FLOWSPEC NLRI*/ /* Parse FLOWSPEC NLRI*/
void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, 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; uint32_t offset = 0;
int type; int type;
@ -90,6 +91,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
char extra[2] = ""; char extra[2] = "";
char pre_extra[2] = ""; char pre_extra[2] = "";
const struct message *bgp_flowspec_display; const struct message *bgp_flowspec_display;
enum bgp_flowspec_util_nlri_t type_util;
if (format == NLRI_STRING_FORMAT_LARGE) { if (format == NLRI_STRING_FORMAT_LARGE) {
snprintf(pre_extra, sizeof(pre_extra), "\t"); 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; bgp_flowspec_display = bgp_flowspec_display_large;
} else } else
bgp_flowspec_display = bgp_flowspec_display_min; 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; error = 0;
while (offset < len-1 && error >= 0) { while (offset < len-1 && error >= 0) {
type = nlri_content[offset]; 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_DEST_PREFIX:
case FLOWSPEC_SRC_PREFIX: case FLOWSPEC_SRC_PREFIX:
ret = bgp_flowspec_ip_address( ret = bgp_flowspec_ip_address(
BGP_FLOWSPEC_RETURN_STRING, type_util,
nlri_content+offset, nlri_content+offset,
len - offset, len - offset,
local_string, &error); local_string, &error);
if (ret <= 0) if (ret <= 0)
break; 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); FS_STRING_UPDATE(count, ptr, format);
ptr += sprintf(ptr, "%s%s %s%s", pre_extra, ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
lookup_msg(bgp_flowspec_display, type, ""), 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_SRC_PORT:
case FLOWSPEC_ICMP_TYPE: case FLOWSPEC_ICMP_TYPE:
case FLOWSPEC_ICMP_CODE: case FLOWSPEC_ICMP_CODE:
ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_RETURN_STRING, ret = bgp_flowspec_op_decode(type_util,
nlri_content+offset, nlri_content+offset,
len - offset, len - offset,
local_string, &error); local_string, &error);
if (ret <= 0) if (ret <= 0)
break; 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); FS_STRING_UPDATE(count, ptr, format);
ptr += sprintf(ptr, "%s%s %s%s", pre_extra, ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
lookup_msg(bgp_flowspec_display, lookup_msg(bgp_flowspec_display,
@ -136,12 +152,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
break; break;
case FLOWSPEC_TCP_FLAGS: case FLOWSPEC_TCP_FLAGS:
ret = bgp_flowspec_tcpflags_decode( ret = bgp_flowspec_tcpflags_decode(
BGP_FLOWSPEC_RETURN_STRING, type_util,
nlri_content+offset, nlri_content+offset,
len - offset, len - offset,
local_string, &error); local_string, &error);
if (ret <= 0) if (ret <= 0)
break; 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); FS_STRING_UPDATE(count, ptr, format);
ptr += sprintf(ptr, "%s%s %s%s", pre_extra, ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
lookup_msg(bgp_flowspec_display, type, ""), 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_PKT_LEN:
case FLOWSPEC_DSCP: case FLOWSPEC_DSCP:
ret = bgp_flowspec_op_decode( ret = bgp_flowspec_op_decode(
BGP_FLOWSPEC_RETURN_STRING, type_util,
nlri_content + offset, nlri_content + offset,
len - offset, local_string, len - offset, local_string,
&error); &error);
if (ret <= 0) if (ret <= 0)
break; 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); FS_STRING_UPDATE(count, ptr, format);
ptr += sprintf(ptr, "%s%s %s%s", pre_extra, ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
lookup_msg(bgp_flowspec_display, lookup_msg(bgp_flowspec_display,
@ -164,12 +192,19 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
break; break;
case FLOWSPEC_FRAGMENT: case FLOWSPEC_FRAGMENT:
ret = bgp_flowspec_fragment_type_decode( ret = bgp_flowspec_fragment_type_decode(
BGP_FLOWSPEC_RETURN_STRING, type_util,
nlri_content + offset, nlri_content + offset,
len - offset, local_string, len - offset, local_string,
&error); &error);
if (ret <= 0) if (ret <= 0)
break; 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); FS_STRING_UPDATE(count, ptr, format);
ptr += sprintf(ptr, "%s%s %s%s", pre_extra, ptr += sprintf(ptr, "%s%s %s%s", pre_extra,
lookup_msg(bgp_flowspec_display, lookup_msg(bgp_flowspec_display,
@ -191,11 +226,21 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
struct attr *attr; struct attr *attr;
char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
char *s; 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 */ /* Print prefix */
if (p != NULL) { if (p != NULL) {
if (p->family != AF_FLOWSPEC) if (p->family != AF_FLOWSPEC)
return; 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) if (display == NLRI_STRING_FORMAT_LARGE)
vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n", vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n",
binfo->flags); 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.ptr,
p->u.prefix_flowspec.prefixlen, p->u.prefix_flowspec.prefixlen,
return_string, return_string,
display); display,
json_nlri_path);
if (display == NLRI_STRING_FORMAT_LARGE) if (display == NLRI_STRING_FORMAT_LARGE)
vty_out(vty, "%s", return_string); vty_out(vty, "%s", return_string);
else if (display == NLRI_STRING_FORMAT_DEBUG) else if (display == NLRI_STRING_FORMAT_DEBUG)
vty_out(vty, "%s", return_string); vty_out(vty, "%s", return_string);
else else if (display == NLRI_STRING_FORMAT_MIN)
vty_out(vty, " %-30s", return_string); 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) if (!binfo)
return; return;
@ -222,16 +270,27 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
return; return;
if (display == NLRI_STRING_FORMAT_LARGE) if (display == NLRI_STRING_FORMAT_LARGE)
vty_out(vty, "\t%s\n", s); vty_out(vty, "\t%s\n", s);
else else if (display == NLRI_STRING_FORMAT_MIN)
vty_out(vty, "%s", s); 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); XFREE(MTYPE_ECOMMUNITY_STR, s);
} }
if (display == NLRI_STRING_FORMAT_LARGE) { peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
char timebuf[BGP_UPTIME_LEN]; if (display == NLRI_STRING_FORMAT_LARGE)
vty_out(vty, "\tup for %8s\n", timebuf);
vty_out(vty, "\tup for %8s\n", else if (json_paths) {
peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, json_time_path = json_object_new_object();
0, NULL)); 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; struct bgp_node *rn;
unsigned long total_count = 0; unsigned long total_count = 0;
json_object *json_paths = NULL; json_object *json_paths = NULL;
int display; int display = NLRI_STRING_FORMAT_LARGE;
if (type != bgp_show_type_detail) if (type != bgp_show_type_detail)
return CMD_SUCCESS; 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)) { for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
if (rn->info == NULL) if (rn->info == NULL)
continue; continue;
if (use_json) {
json_paths = json_object_new_array();
display = NLRI_STRING_FORMAT_JSON;
}
for (ri = rn->info; ri; ri = ri->next) { for (ri = rn->info; ri; ri = ri->next) {
total_count++; total_count++;
route_vty_out_flowspec(vty, &rn->p, 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); 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, vty_out(vty,
"\nDisplayed %ld flowspec entries\n", "\nDisplayed %ld flowspec entries\n",
total_count); total_count);

View File

@ -6319,6 +6319,8 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
#endif #endif
} else if (p->family == AF_FLOWSPEC) { } else if (p->family == AF_FLOWSPEC) {
route_vty_out_flowspec(vty, p, NULL, route_vty_out_flowspec(vty, p, NULL,
json ?
NLRI_STRING_FORMAT_JSON_SIMPLE :
NLRI_STRING_FORMAT_MIN, json); NLRI_STRING_FORMAT_MIN, json);
} else { } else {
if (!json) if (!json)
@ -6511,9 +6513,10 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
"used"); "used");
} else } else
vty_out(vty, "%-16s", inet_ntoa(attr->nexthop)); vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
} } else if (safi == SAFI_FLOWSPEC) {
/* already done */
/* IPv4 Next Hop */ /* 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) { if (json_paths) {
json_nexthop_global = json_object_new_object(); json_nexthop_global = json_object_new_object();