summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_clist.c11
-rw-r--r--bgpd/bgp_lcommunity.c154
-rw-r--r--bgpd/bgp_lcommunity.h11
-rw-r--r--bgpd/bgp_route.c10
-rw-r--r--bgpd/bgp_vty.c48
5 files changed, 124 insertions, 110 deletions
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index d1bc7f6e5..7cf147754 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -512,7 +512,7 @@ static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
if (com == NULL || com->size == 0)
str = "";
else
- str = lcommunity_str(com);
+ str = lcommunity_str(com, false);
/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0)
@@ -986,13 +986,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
entry->any = (str ? 0 : 1);
entry->u.lcom = lcom;
entry->reg = regex;
- if (lcom)
- entry->config = lcommunity_lcom2str(
- lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
- else if (regex)
- entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
- else
- entry->config = NULL;
+ entry->config =
+ (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
/* Do not put duplicated community entry. */
if (community_list_dup_check(list, entry))
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index 09b3a8718..33f4d139b 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -160,15 +160,6 @@ struct lcommunity *lcommunity_dup(struct lcommunity *lcom)
return new;
}
-/* Retrun string representation of communities attribute. */
-char *lcommunity_str(struct lcommunity *lcom)
-{
- if (!lcom->str)
- lcom->str =
- lcommunity_lcom2str(lcom, LCOMMUNITY_FORMAT_DISPLAY);
- return lcom->str;
-}
-
/* Merge two Large Communities Attribute structure. */
struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
struct lcommunity *lcom2)
@@ -186,6 +177,80 @@ struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
return lcom1;
}
+static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
+{
+ int i;
+ int len;
+ bool first = 1;
+ char *str_buf;
+ char *str_pnt;
+ uint8_t *pnt;
+ uint32_t global, local1, local2;
+ json_object *json_lcommunity_list = NULL;
+ json_object *json_string = NULL;
+
+#define LCOMMUNITY_STR_DEFAULT_LEN 32
+
+ if (!lcom)
+ return;
+
+ if (make_json) {
+ lcom->json = json_object_new_object();
+ json_lcommunity_list = json_object_new_array();
+ }
+
+ if (lcom->size == 0) {
+ str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1);
+ str_buf[0] = '\0';
+
+ if (make_json) {
+ json_object_string_add(lcom->json, "string", "");
+ json_object_object_add(lcom->json, "list",
+ json_lcommunity_list);
+ }
+
+ lcom->str = str_buf;
+ return;
+ }
+
+ str_buf = str_pnt =
+ XMALLOC(MTYPE_LCOMMUNITY_STR,
+ (LCOMMUNITY_STR_DEFAULT_LEN * lcom->size) + 1);
+
+ for (i = 0; i < lcom->size; i++) {
+ if (first)
+ first = 0;
+ else
+ *str_pnt++ = ' ';
+
+ pnt = lcom->val + (i * LCOMMUNITY_SIZE);
+ pnt = ptr_get_be32(pnt, &global);
+ pnt = ptr_get_be32(pnt, &local1);
+ pnt = ptr_get_be32(pnt, &local2);
+ (void)pnt;
+
+ len = sprintf(str_pnt, "%u:%u:%u", global, local1, local2);
+ if (make_json) {
+ json_string = json_object_new_string(str_pnt);
+ json_object_array_add(json_lcommunity_list,
+ json_string);
+ }
+
+ str_pnt += len;
+ }
+
+ str_buf =
+ XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, str_pnt - str_buf + 1);
+
+ if (make_json) {
+ json_object_string_add(lcom->json, "string", str_buf);
+ json_object_object_add(lcom->json, "list",
+ json_lcommunity_list);
+ }
+
+ lcom->str = str_buf;
+}
+
/* Intern Large Communities Attribute. */
struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
{
@@ -201,8 +266,7 @@ struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
find->refcnt++;
if (!find->str)
- find->str =
- lcommunity_lcom2str(find, LCOMMUNITY_FORMAT_DISPLAY);
+ set_lcommunity_string(find, false);
return find;
}
@@ -225,6 +289,21 @@ void lcommunity_unintern(struct lcommunity **lcom)
}
}
+/* Retrun string representation of communities attribute. */
+char *lcommunity_str(struct lcommunity *lcom, bool make_json)
+{
+ if (!lcom)
+ return NULL;
+
+ if (make_json && !lcom->json && lcom->str)
+ XFREE(MTYPE_LCOMMUNITY_STR, lcom->str);
+
+ if (!lcom->str)
+ set_lcommunity_string(lcom, make_json);
+
+ return lcom->str;
+}
+
/* Utility function to make hash key. */
unsigned int lcommunity_hash_make(void *arg)
{
@@ -388,59 +467,6 @@ int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
return 0;
}
-/* Convert large community attribute to string.
- The large coms will be in 65535:65531:0 format.
-*/
-char *lcommunity_lcom2str(struct lcommunity *lcom, int format)
-{
- int i;
- uint8_t *pnt;
-#define LCOMMUNITY_STR_DEFAULT_LEN 40
- int str_size;
- int str_pnt;
- char *str_buf;
- int len = 0;
- int first = 1;
- uint32_t globaladmin, localdata1, localdata2;
-
- if (lcom->size == 0) {
- str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1);
- str_buf[0] = '\0';
- return str_buf;
- }
-
- /* Prepare buffer. */
- str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
- str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
- str_pnt = 0;
-
- for (i = 0; i < lcom->size; i++) {
- /* Make it sure size is enough. */
- while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) {
- str_size *= 2;
- str_buf = XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf,
- str_size);
- }
-
- /* Space between each value. */
- if (!first)
- str_buf[str_pnt++] = ' ';
-
- pnt = lcom->val + (i * LCOMMUNITY_SIZE);
-
- pnt = ptr_get_be32(pnt, &globaladmin);
- pnt = ptr_get_be32(pnt, &localdata1);
- pnt = ptr_get_be32(pnt, &localdata2);
- (void)pnt; /* consume value */
-
- len = sprintf(str_buf + str_pnt, "%u:%u:%u", globaladmin,
- localdata1, localdata2);
- str_pnt += len;
- first = 0;
- }
- return str_buf;
-}
-
int lcommunity_match(const struct lcommunity *lcom1,
const struct lcommunity *lcom2)
{
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
index 78841accf..c88a01639 100644
--- a/bgpd/bgp_lcommunity.h
+++ b/bgpd/bgp_lcommunity.h
@@ -21,10 +21,7 @@
#ifndef _QUAGGA_BGP_LCOMMUNITY_H
#define _QUAGGA_BGP_LCOMMUNITY_H
-/* Extended communities attribute string format. */
-#define LCOMMUNITY_FORMAT_ROUTE_MAP 0
-#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1
-#define LCOMMUNITY_FORMAT_DISPLAY 2
+#include "lib/json.h"
/* Large Communities value is twelve octets long. */
#define LCOMMUNITY_SIZE 12
@@ -40,6 +37,9 @@ struct lcommunity {
/* Large Communities value. */
uint8_t *val;
+ /* Large Communities as a json object */
+ json_object *json;
+
/* Human readable format string. */
char *str;
};
@@ -65,10 +65,9 @@ extern void lcommunity_unintern(struct lcommunity **);
extern unsigned int lcommunity_hash_make(void *);
extern struct hash *lcommunity_hash(void);
extern struct lcommunity *lcommunity_str2com(const char *);
-extern char *lcommunity_lcom2str(struct lcommunity *, int);
extern int lcommunity_match(const struct lcommunity *,
const struct lcommunity *);
-extern char *lcommunity_str(struct lcommunity *);
+extern char *lcommunity_str(struct lcommunity *, bool make_json);
extern int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr);
extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr);
#endif /* _QUAGGA_BGP_LCOMMUNITY_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 997d708ba..c0683b84a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -7414,7 +7414,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
json_object *json_cluster_list = NULL;
json_object *json_cluster_list_list = NULL;
json_object *json_ext_community = NULL;
- json_object *json_lcommunity = NULL;
json_object *json_last_update = NULL;
json_object *json_pmsi = NULL;
json_object *json_nexthop_global = NULL;
@@ -8041,13 +8040,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line 6 display Large community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
if (json_paths) {
- json_lcommunity = json_object_new_object();
- json_object_string_add(json_lcommunity,
- "string",
- attr->lcommunity->str);
+ if (!attr->lcommunity->json)
+ lcommunity_str(attr->lcommunity, true);
+ json_object_lock(attr->lcommunity->json);
json_object_object_add(json_path,
"largeCommunity",
- json_lcommunity);
+ attr->lcommunity->json);
} else {
vty_out(vty, " Large Community: %s\n",
attr->lcommunity->str);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b8c81232b..35477ba16 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -10859,7 +10859,7 @@ static void lcommunity_show_all_iterator(struct hash_backet *backet,
lcom = (struct lcommunity *)backet->data;
vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt,
- lcommunity_str(lcom));
+ lcommunity_str(lcom, false));
}
/* Show BGP's community internal data. */
@@ -13606,6 +13606,24 @@ DEFUN (no_ip_community_list_expanded_all,
return CMD_SUCCESS;
}
+/* Return configuration string of community-list entry. */
+static const char *community_list_config_str(struct community_entry *entry)
+{
+ const char *str;
+
+ if (entry->any)
+ str = "";
+ else {
+ if (entry->style == COMMUNITY_LIST_STANDARD)
+ str = community_str(entry->u.com, false);
+ else if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ str = lcommunity_str(entry->u.lcom, false);
+ else
+ str = entry->config;
+ }
+ return str;
+}
+
static void community_list_show(struct vty *vty, struct community_list *list)
{
struct community_entry *entry;
@@ -13631,9 +13649,7 @@ static void community_list_show(struct vty *vty, struct community_list *list)
else
vty_out(vty, " %s %s\n",
community_direct_str(entry->direct),
- entry->style == COMMUNITY_LIST_STANDARD
- ? community_str(entry->u.com, false)
- : entry->config);
+ community_list_config_str(entry));
}
}
@@ -13985,9 +14001,7 @@ static void lcommunity_list_show(struct vty *vty, struct community_list *list)
else
vty_out(vty, " %s %s\n",
community_direct_str(entry->direct),
- entry->style == EXTCOMMUNITY_LIST_STANDARD
- ? entry->u.ecom->str
- : entry->config);
+ community_list_config_str(entry));
}
}
@@ -14222,9 +14236,7 @@ static void extcommunity_list_show(struct vty *vty, struct community_list *list)
else
vty_out(vty, " %s %s\n",
community_direct_str(entry->direct),
- entry->style == EXTCOMMUNITY_LIST_STANDARD
- ? entry->u.ecom->str
- : entry->config);
+ community_list_config_str(entry));
}
}
@@ -14275,22 +14287,6 @@ DEFUN (show_ip_extcommunity_list_arg,
return CMD_SUCCESS;
}
-/* Return configuration string of community-list entry. */
-static const char *community_list_config_str(struct community_entry *entry)
-{
- const char *str;
-
- if (entry->any)
- str = "";
- else {
- if (entry->style == COMMUNITY_LIST_STANDARD)
- str = community_str(entry->u.com, false);
- else
- str = entry->config;
- }
- return str;
-}
-
/* Display community-list and extcommunity-list configuration. */
static int community_list_config_write(struct vty *vty)
{