diff options
-rw-r--r-- | bgpd/bgp_clist.c | 11 | ||||
-rw-r--r-- | bgpd/bgp_lcommunity.c | 154 | ||||
-rw-r--r-- | bgpd/bgp_lcommunity.h | 11 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 48 |
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) { |