Commit b1bfb91799 for frr
commit b1bfb91799a02ad4e8400cc0e7d2083e93bc1750
Author: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Thu Oct 15 18:30:24 2026 +0300
bgpd: Avoid changing interned attributes cached values
We store X->str (aka human-readable string) for communities, as-path.
The problem is that with the "show" commands we change X->str value while
the attribute is already internet.
With this change let's separate JSON and X->str caching as well, because
if we need to update the JSON only, we shouldn't free/create X->str again.
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index cc9bf1ab76..a235a01a85 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -523,29 +523,15 @@ bool aspath_has_as4(struct aspath *aspath)
}
/* Convert aspath structure to string expression. */
-static void aspath_make_str_count(struct aspath *as, bool make_json)
+static void aspath_make_str_count(struct aspath *as)
{
struct assegment *seg;
int str_size;
int len = 0;
char *str_buf;
- json_object *jaspath_segments = NULL;
- json_object *jseg = NULL;
- json_object *jseg_list = NULL;
-
- if (make_json) {
- as->json = json_object_new_object();
- jaspath_segments = json_object_new_array();
- }
/* Empty aspath. */
if (!as->segments) {
- if (make_json) {
- 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;
@@ -588,9 +574,6 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
XFREE(MTYPE_AS_STR, str_buf);
as->str = NULL;
as->str_len = 0;
- json_object_free(as->json);
- as->json = NULL;
- json_object_free(jaspath_segments);
return;
}
@@ -616,14 +599,8 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
str_buf + len, str_size - len, "%c",
aspath_delimiter_char(seg->type, AS_SEG_START));
- if (make_json)
- jseg_list = json_object_new_array();
-
/* write out the ASNs, with their separators, bar the last one*/
for (i = 0; i < seg->length; i++) {
- if (make_json)
- asn_asn2json_array(jseg_list, seg->as[i],
- as->asnotation);
len += snprintfrr(str_buf + len, str_size - len,
ASN_FORMAT(as->asnotation),
&seg->as[i]);
@@ -633,15 +610,6 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
"%c", separator);
}
- if (make_json) {
- 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",
@@ -658,16 +626,10 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
as->str = str_buf;
as->str_len = len;
- if (make_json) {
- 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;
}
-void aspath_str_update(struct aspath *as, bool make_json)
+void aspath_str_update(struct aspath *as)
{
XFREE(MTYPE_AS_STR, as->str);
@@ -676,7 +638,38 @@ void aspath_str_update(struct aspath *as, bool make_json)
as->json = NULL;
}
- aspath_make_str_count(as, make_json);
+ aspath_make_str_count(as);
+}
+
+/* Build the JSON representation, leaving as->str untouched. */
+void aspath_json_update(struct aspath *as)
+{
+ struct assegment *seg;
+ json_object *jaspath_segments;
+ json_object *jseg;
+ json_object *jseg_list;
+ int i;
+
+ if (as->json)
+ json_object_free(as->json);
+
+ as->json = json_object_new_object();
+ jaspath_segments = json_object_new_array();
+
+ for (seg = as->segments; seg; seg = seg->next) {
+ jseg_list = json_object_new_array();
+ for (i = 0; i < seg->length; i++)
+ asn_asn2json_array(jseg_list, seg->as[i], as->asnotation);
+
+ 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);
+ }
+
+ json_object_string_add(as->json, "string", as->segments ? as->str : "Local");
+ json_object_object_add(as->json, "segments", jaspath_segments);
+ json_object_int_add(as->json, "length", aspath_count_hops(as));
}
/* Intern allocated AS path. */
@@ -930,7 +923,7 @@ static struct aspath *aspath_add_asns_rightmost(struct aspath *aspath, as_t asno
}
}
- aspath_str_update(aspath, false);
+ aspath_str_update(aspath);
aspath->count = aspath_count_hops_internal(aspath);
return aspath;
}
@@ -1146,7 +1139,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
}
assegment_normalise(aspath->segments);
- aspath_str_update(aspath, false);
+ aspath_str_update(aspath);
aspath->count = aspath_count_hops_internal(aspath);
return aspath;
@@ -1301,7 +1294,7 @@ struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
cur_seg = cur_seg->next;
}
- aspath_str_update(new, false);
+ aspath_str_update(new);
new->count = aspath_count_hops_internal(new);
return new;
}
@@ -1327,7 +1320,7 @@ struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
seg = seg->next;
}
- aspath_str_update(new, false);
+ aspath_str_update(new);
new->count = aspath_count_hops_internal(new);
return new;
@@ -1351,7 +1344,7 @@ struct aspath *aspath_replace_all_asn(struct aspath *aspath, as_t our_asn)
seg = seg->next;
}
- aspath_str_update(new, false);
+ aspath_str_update(new);
new->count = aspath_count_hops_internal(new);
return new;
@@ -1379,7 +1372,7 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn,
seg = seg->next;
}
- aspath_str_update(new, false);
+ aspath_str_update(new);
new->count = aspath_count_hops_internal(new);
return new;
@@ -1453,7 +1446,7 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn)
}
if (!aspath->refcnt)
aspath_free(aspath);
- aspath_str_update(new, false);
+ aspath_str_update(new);
new->count = aspath_count_hops_internal(new);
return new;
}
@@ -1510,7 +1503,7 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2)
if (last)
last->next = as2->segments;
as2->segments = new;
- aspath_str_update(as2, false);
+ aspath_str_update(as2);
as2->count = aspath_count_hops_internal(as2);
return as2;
}
@@ -1528,7 +1521,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* If as2 is empty, only need to dupe as1's chain onto as2 */
if (as2->segments == NULL) {
as2->segments = assegment_dup_all(as1->segments);
- aspath_str_update(as2, false);
+ aspath_str_update(as2);
as2->count = aspath_count_hops_internal(as2);
return as2;
}
@@ -1549,7 +1542,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
if (!as2->segments) {
as2->segments = assegment_dup_all(as1->segments);
- aspath_str_update(as2, false);
+ aspath_str_update(as2);
as2->count = aspath_count_hops_internal(as2);
return as2;
}
@@ -1595,7 +1588,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* we've now prepended as1's segment chain to as2, merging
* the in between AS_SEQUENCE of seg2 in the process
*/
- aspath_str_update(as2, false);
+ aspath_str_update(as2);
as2->count = aspath_count_hops_internal(as2);
return as2;
} else {
@@ -1707,7 +1700,7 @@ struct aspath *aspath_filter_exclude(struct aspath *source,
lastseg->next = newseg;
lastseg = newseg;
}
- aspath_str_update(newpath, false);
+ aspath_str_update(newpath);
newpath->count = aspath_count_hops_internal(newpath);
/* We are happy returning even an empty AS_PATH, because the
* administrator
@@ -1726,7 +1719,7 @@ struct aspath *aspath_filter_exclude_all(struct aspath *source)
newpath = aspath_new(source->asnotation);
- aspath_str_update(newpath, false);
+ aspath_str_update(newpath);
newpath->count = aspath_count_hops_internal(newpath);
/* We are happy returning even an empty AS_PATH, because the
* administrator
@@ -1814,7 +1807,7 @@ struct aspath *aspath_filter_exclude_acl(struct aspath *source,
}
- aspath_str_update(source, false);
+ aspath_str_update(source);
source->count = aspath_count_hops_internal(source);
/* We are happy returning even an empty AS_PATH, because the
* administrator
@@ -1851,7 +1844,7 @@ static struct aspath *aspath_add_asns(struct aspath *aspath, as_t asno, uint8_t
aspath->segments = newsegment;
}
- aspath_str_update(aspath, false);
+ aspath_str_update(aspath);
aspath->count = aspath_count_hops_internal(aspath);
return aspath;
}
@@ -1940,7 +1933,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
if (!hops) {
newpath = aspath_dup(as4path);
- aspath_str_update(newpath, false);
+ aspath_str_update(newpath);
/* dup sets the count properly */
return newpath;
}
@@ -2002,7 +1995,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
mergedpath = aspath_merge(newpath, aspath_dup(as4path));
aspath_free(newpath);
mergedpath->segments = assegment_normalise(mergedpath->segments);
- aspath_str_update(mergedpath, false);
+ aspath_str_update(mergedpath);
mergedpath->count = aspath_count_hops_internal(mergedpath);
if (BGP_DEBUG(as4, AS4))
@@ -2075,7 +2068,7 @@ struct aspath *aspath_delete_confed_seq(struct aspath *aspath)
}
if (removed_confed_segment) {
- aspath_str_update(aspath, false);
+ aspath_str_update(aspath);
aspath->count = aspath_count_hops_internal(aspath);
}
@@ -2128,7 +2121,7 @@ struct aspath *aspath_empty_get(void)
struct aspath *aspath;
aspath = aspath_new(bgp_get_asnotation(NULL));
- aspath_make_str_count(aspath, false);
+ aspath_make_str_count(aspath);
return aspath;
}
@@ -2269,7 +2262,7 @@ struct aspath *aspath_str2aspath(const char *str,
}
}
- aspath_make_str_count(aspath, false);
+ aspath_make_str_count(aspath);
return aspath;
}
@@ -2281,7 +2274,7 @@ unsigned int aspath_key_make(const void *p)
unsigned int key = 0;
if (!aspath->str)
- aspath_str_update((struct aspath *)aspath, false);
+ aspath_str_update((struct aspath *)aspath);
key = jhash(aspath->str, aspath->str_len, 2334325);
@@ -2558,7 +2551,7 @@ struct aspath *aspath_delete_as_set_seq(struct aspath *aspath)
}
if (removed) {
- aspath_str_update(aspath, false);
+ aspath_str_update(aspath);
aspath->count = aspath_count_hops_internal(aspath);
}
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 295837b137..ce4df29bdd 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -110,7 +110,8 @@ extern struct aspath *aspath_empty(enum asnotation_mode asnotation);
extern struct aspath *aspath_empty_get(void);
extern struct aspath *aspath_str2aspath(const char *str,
enum asnotation_mode asnotation);
-extern void aspath_str_update(struct aspath *as, bool make_json);
+extern void aspath_str_update(struct aspath *as);
+extern void aspath_json_update(struct aspath *as);
extern void aspath_free(struct aspath *aspath);
extern struct aspath *aspath_intern(struct aspath *aspath);
extern void aspath_unintern(struct aspath **aspath);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index bb596e54d5..e8fd2d8953 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1377,8 +1377,7 @@ static void attr_show_all_iterator(struct hash_bucket *bucket, void *args[])
attr->nh_ifindex, attr->nh_flags, attr->distance, &attr->mp_nexthop_global,
&attr->mp_nexthop_local, attr->nh_lla_ifindex);
vty_out(vty, "\taspath: %s Community: %s Large Community: %s\n", aspath_print(attr->aspath),
- community_str(attr->community, false, false),
- lcommunity_str(attr->lcommunity, false, false));
+ community_str(attr->community, false), lcommunity_str(attr->lcommunity, false));
vty_out(vty, "\tExtended Community: %s Extended IPv6 Community: %s\n",
ecommunity_str(attr->ecommunity),
ecommunity_str(bgp_attr_get_ipv6_ecommunity(attr)));
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 8b244bd703..f9f4ca9ed9 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -18,7 +18,6 @@
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
-#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
@@ -532,33 +531,16 @@ static bool community_regexp_include(struct frregex *reg, struct community *com,
static bool community_regexp_match(struct community *com, struct frregex *reg)
{
const char *str;
- char *regstr;
- int rv;
- bool translate_alias = !!bgp_ca_alias_hash->count;
/* When there is no communities attribute it is treated as empty
string. */
if (com == NULL || com->size == 0)
return false;
- str = community_str(com, false, translate_alias);
-
- /* If at least one community alias is configured, then let's
- * do the work, otherwise we don't need to spend time on splitting
- * stuff and creating a new string.
- */
- regstr = translate_alias ? bgp_alias2community_str(str) : (char *)str;
+ str = community_str(com, false);
/* Regular expression match. */
- rv = regexec(®->real, regstr, 0, NULL, 0);
-
- /* This is allocated by frrstr_join(), and needs to be freed
- * only if it was created.
- */
- if (translate_alias)
- XFREE(MTYPE_TMP, regstr);
-
- return rv == 0;
+ return regexec(®->real, str, 0, NULL, 0) == 0;
}
static char *ecommunity_str_get(struct ecommunity *ecom, int i)
@@ -642,33 +624,16 @@ static bool ecommunity_regexp_include(struct frregex *reg, struct ecommunity *ec
static bool lcommunity_regexp_match(struct lcommunity *com, struct frregex *reg)
{
const char *str;
- char *regstr;
- int rv;
- bool translate_alias = !!bgp_ca_alias_hash->count;
/* When there is no communities attribute it is treated as empty
string. */
if (com == NULL || com->size == 0)
return false;
- str = lcommunity_str(com, false, translate_alias);
-
- /* If at least one community alias is configured, then let's
- * do the work, otherwise we don't need to spend time on splitting
- * stuff and creating a new string.
- */
- regstr = translate_alias ? bgp_alias2community_str(str) : (char *)str;
+ str = lcommunity_str(com, false);
/* Regular expression match. */
- rv = regexec(®->real, regstr, 0, NULL, 0);
-
- /* This is allocated by frrstr_join(), and needs to be freed
- * only if it was created.
- */
- if (translate_alias)
- XFREE(MTYPE_TMP, regstr);
-
- return rv == 0;
+ return regexec(®->real, str, 0, NULL, 0) == 0;
}
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 7bc64f634f..dd5304e456 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -184,8 +184,7 @@ struct community *community_uniq_sort(struct community *com)
0xFFFFFF04 "no-peer"
For other values, "AS:VAL" format is used. */
-static void set_community_string(struct community *com, bool make_json,
- bool translate_alias)
+static void set_community_string(struct community *com, bool make_json)
{
int i;
char *str;
@@ -217,8 +216,7 @@ static void set_community_string(struct community *com, bool make_json,
json_object_object_add(com->json, "list",
json_community_list);
}
- com->str = str;
- return;
+ goto out;
}
/* Memory allocation is time consuming work. So we calculate
@@ -279,7 +277,7 @@ static void set_community_string(struct community *com, bool make_json,
val = CHECK_FLAG(comval, 0xFFFF);
snprintf(buf, sizeof(buf), "%u:%d", as, val);
- const char *com2alias = translate_alias ? bgp_community2alias(buf) : buf;
+ const char *com2alias = make_json ? bgp_community2alias(buf) : buf;
/* Plus one for the space separator. */
len += strlen(com2alias) + 1;
@@ -432,8 +430,7 @@ static void set_community_string(struct community *com, bool make_json,
val = CHECK_FLAG(comval, 0xFFFF);
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
- const char *com2alias =
- translate_alias ? bgp_community2alias(buf) : buf;
+ const char *com2alias = make_json ? bgp_community2alias(buf) : buf;
strlcat(str, com2alias, len);
if (make_json) {
@@ -449,7 +446,12 @@ static void set_community_string(struct community *com, bool make_json,
json_object_string_add(com->json, "string", str);
json_object_object_add(com->json, "list", json_community_list);
}
- com->str = str;
+
+out:
+ if (!com->str && !make_json)
+ com->str = str;
+ else
+ XFREE(MTYPE_COMMUNITY_STR, str);
}
/* Intern communities attribute. */
@@ -473,7 +475,7 @@ struct community *community_intern(struct community *com)
/* Make string. */
if (!find->str)
- set_community_string(find, false, true);
+ set_community_string(find, false);
return find;
}
@@ -534,16 +536,15 @@ struct community *community_dup(struct community *com)
}
/* Return string representation of communities attribute. */
-char *community_str(struct community *com, bool make_json, bool translate_alias)
+char *community_str(struct community *com, bool make_json)
{
if (!com)
return NULL;
- if (make_json && !com->json && com->str)
- XFREE(MTYPE_COMMUNITY_STR, com->str);
-
if (!com->str)
- set_community_string(com, make_json, translate_alias);
+ set_community_string(com, false);
+ if (make_json && !com->json)
+ set_community_string(com, true);
return com->str;
}
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index b172207144..9dd7df18c6 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -62,8 +62,7 @@ extern struct community *community_uniq_sort(struct community *com);
extern struct community *community_parse(uint32_t *pnt, unsigned short length);
extern struct community *community_intern(struct community *com);
extern void community_unintern(struct community **com);
-extern char *community_str(struct community *com, bool make_json,
- bool translate_alias);
+extern char *community_str(struct community *com, bool make_json);
extern unsigned int community_hash_make(const struct community *com);
extern struct community *community_str2com(const char *str);
extern bool community_match(const struct community *com1,
diff --git a/bgpd/bgp_community_alias.c b/bgpd/bgp_community_alias.c
index d7567fcdd4..c10e1ac513 100644
--- a/bgpd/bgp_community_alias.c
+++ b/bgpd/bgp_community_alias.c
@@ -159,31 +159,30 @@ const char *bgp_alias2community(char *alias)
return alias;
}
-/* Communities structs have `->str` which is used
- * for vty outputs and extended BGP community lists
- * with regexp.
- * This is a helper to convert already aliased version
- * of communities into numerical-only format.
+/* Communities structs cache `->str` without aliases (AS:VAL and
+ * well-known names only), which is used for matching.
+ * This is a helper to convert it into the aliased version
+ * for outputs. The result must be freed with MTYPE_TMP.
*/
-char *bgp_alias2community_str(const char *str)
+char *bgp_community2alias_str(const char *str)
{
- char **aliases;
- char *comstr;
+ char **communities;
+ char *aliasstr;
int num, i;
- frrstr_split(str, " ", &aliases, &num);
- const char *communities[num];
+ frrstr_split(str, " ", &communities, &num);
+ const char *aliases[num];
for (i = 0; i < num; i++)
- communities[i] = bgp_alias2community(aliases[i]);
+ aliases[i] = bgp_community2alias(communities[i]);
- comstr = frrstr_join(communities, num, " ");
+ aliasstr = frrstr_join(aliases, num, " ");
for (i = 0; i < num; i++)
- XFREE(MTYPE_TMP, aliases[i]);
- XFREE(MTYPE_TMP, aliases);
+ XFREE(MTYPE_TMP, communities[i]);
+ XFREE(MTYPE_TMP, communities);
- return comstr;
+ return aliasstr;
}
static int bgp_community_alias_vector_walker(struct hash_bucket *bucket,
diff --git a/bgpd/bgp_community_alias.h b/bgpd/bgp_community_alias.h
index 9dcab6fe30..a9466fdebc 100644
--- a/bgpd/bgp_community_alias.h
+++ b/bgpd/bgp_community_alias.h
@@ -30,7 +30,7 @@ extern void bgp_ca_alias_delete(struct community_alias *ca);
extern int bgp_community_alias_write(struct vty *vty);
extern const char *bgp_community2alias(char *community);
extern const char *bgp_alias2community(char *alias);
-extern char *bgp_alias2community_str(const char *str);
+extern char *bgp_community2alias_str(const char *str);
extern void bgp_community_alias_command_completion_setup(void);
#endif /* FRR_BGP_COMMUNITY_ALIAS_H */
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index f165335c9a..da27833d19 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -25,6 +25,7 @@
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
@@ -445,13 +446,21 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
if (bgp_attr_exists(attr, BGP_ATTR_MULTI_EXIT_DISC))
snprintfrr(buf + strlen(buf), size - strlen(buf), ", metric %u", attr->med);
- if (bgp_attr_exists(attr, BGP_ATTR_COMMUNITIES))
- snprintfrr(buf + strlen(buf), size - strlen(buf), ", community %s",
- community_str(bgp_attr_get_community(attr), false, true));
+ if (bgp_attr_exists(attr, BGP_ATTR_COMMUNITIES)) {
+ char *str = bgp_community2alias_str(
+ community_str(bgp_attr_get_community(attr), false));
- if (bgp_attr_exists(attr, BGP_ATTR_LARGE_COMMUNITIES))
- snprintfrr(buf + strlen(buf), size - strlen(buf), ", large-community %s",
- lcommunity_str(bgp_attr_get_lcommunity(attr), false, true));
+ snprintfrr(buf + strlen(buf), size - strlen(buf), ", community %s", str);
+ XFREE(MTYPE_TMP, str);
+ }
+
+ if (bgp_attr_exists(attr, BGP_ATTR_LARGE_COMMUNITIES)) {
+ char *str = bgp_community2alias_str(
+ lcommunity_str(bgp_attr_get_lcommunity(attr), false));
+
+ snprintfrr(buf + strlen(buf), size - strlen(buf), ", large-community %s", str);
+ XFREE(MTYPE_TMP, str);
+ }
if (bgp_attr_exists(attr, BGP_ATTR_EXT_COMMUNITIES))
snprintfrr(buf + strlen(buf), size - strlen(buf), ", extcommunity %s",
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index 57a7981e87..5bc516c2d6 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -161,8 +161,7 @@ struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
return lcom1;
}
-static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
- bool translate_alias)
+static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
{
int i;
int len;
@@ -194,8 +193,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
json_lcommunity_list);
}
- lcom->str = str_buf;
- return;
+ goto out;
}
/* 1 space + lcom->size lcom strings + null terminator */
@@ -224,8 +222,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
* then we need to realloc the memory associated
* with the string so that it can fit
*/
- const char *com2alias =
- translate_alias ? bgp_community2alias(lcsb) : lcsb;
+ const char *com2alias = make_json ? bgp_community2alias(lcsb) : lcsb;
size_t individual_len = strlen(com2alias);
if (individual_len + len > str_buf_sz) {
str_buf_sz = individual_len + len + 1;
@@ -248,7 +245,11 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
json_lcommunity_list);
}
- lcom->str = str_buf;
+out:
+ if (!lcom->str && !make_json)
+ lcom->str = str_buf;
+ else
+ XFREE(MTYPE_LCOMMUNITY_STR, str_buf);
}
/* Intern Large Communities Attribute. */
@@ -266,7 +267,7 @@ struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
find->refcnt++;
if (!find->str)
- set_lcommunity_string(find, false, true);
+ set_lcommunity_string(find, false);
return find;
}
@@ -293,17 +294,15 @@ void lcommunity_unintern(struct lcommunity **lcom)
}
/* Return string representation of lcommunities attribute. */
-char *lcommunity_str(struct lcommunity *lcom, bool make_json,
- bool translate_alias)
+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, translate_alias);
+ set_lcommunity_string(lcom, false);
+ if (make_json && !lcom->json)
+ set_lcommunity_string(lcom, true);
return lcom->str;
}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
index 0c8140e779..03fc2905cd 100644
--- a/bgpd/bgp_lcommunity.h
+++ b/bgpd/bgp_lcommunity.h
@@ -54,8 +54,7 @@ extern unsigned int lcommunity_hash_make(const void *arg);
extern struct hash *lcommunity_hash(void);
extern struct lcommunity *lcommunity_str2com(const char *str);
extern bool lcommunity_match(const struct lcommunity *lcom1, const struct lcommunity *lcom2);
-extern char *lcommunity_str(struct lcommunity *lcom, bool make_json,
- bool translate_alias);
+extern char *lcommunity_str(struct lcommunity *lcom, bool make_json);
extern bool lcommunity_include(struct lcommunity *lcom, uint8_t *ptr);
extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 9e8749ea9d..0a2021ad90 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -13872,7 +13872,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (attr->aspath) {
if (json_paths) {
if (!attr->aspath->json)
- aspath_str_update(attr->aspath, true);
+ aspath_json_update(attr->aspath);
json_object_lock(attr->aspath->json);
json_object_object_add(json_path, "aspath",
attr->aspath->json);
@@ -14476,17 +14476,17 @@ skip_nexthop:
if (bgp_attr_exists(attr, BGP_ATTR_COMMUNITIES)) {
if (json_paths) {
if (!bgp_attr_get_community(attr)->json)
- community_str(bgp_attr_get_community(attr),
- true, true);
+ community_str(bgp_attr_get_community(attr), true);
json_object_lock(bgp_attr_get_community(attr)->json);
json_object_object_add(
json_path, "community",
bgp_attr_get_community(attr)->json);
} else {
- if (!bgp_attr_get_community(attr)->str)
- community_str(bgp_attr_get_community(attr), true, true);
- vty_out(vty, " Community: %s\n",
- bgp_attr_get_community(attr)->str);
+ char *str = bgp_community2alias_str(
+ community_str(bgp_attr_get_community(attr), false));
+
+ vty_out(vty, " Community: %s\n", str);
+ XFREE(MTYPE_TMP, str);
}
}
@@ -14530,17 +14530,17 @@ skip_nexthop:
if (bgp_attr_exists(attr, BGP_ATTR_LARGE_COMMUNITIES)) {
if (json_paths) {
if (!bgp_attr_get_lcommunity(attr)->json)
- lcommunity_str(bgp_attr_get_lcommunity(attr),
- true, true);
+ lcommunity_str(bgp_attr_get_lcommunity(attr), true);
json_object_lock(bgp_attr_get_lcommunity(attr)->json);
json_object_object_add(
json_path, "largeCommunity",
bgp_attr_get_lcommunity(attr)->json);
} else {
- if (!bgp_attr_get_lcommunity(attr)->str)
- lcommunity_str(bgp_attr_get_lcommunity(attr), true, true);
- vty_out(vty, " Large Community: %s\n",
- bgp_attr_get_lcommunity(attr)->str);
+ char *str = bgp_community2alias_str(
+ lcommunity_str(bgp_attr_get_lcommunity(attr), false));
+
+ vty_out(vty, " Large Community: %s\n", str);
+ XFREE(MTYPE_TMP, str);
}
}
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 7460332dd8..35a10e3dc3 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -7168,7 +7168,7 @@ DEFUN_YANG (set_community,
XFREE(MTYPE_TMP, str);
/* Set communities attribute string. */
- str = community_str(com, false, false);
+ str = community_str(com, false);
if (additive) {
size_t argstr_sz = strlen(str) + strlen(" additive") + 1;
diff --git a/bgpd/bgp_unreach.c b/bgpd/bgp_unreach.c
index 9b56f01028..cb4ca33e79 100644
--- a/bgpd/bgp_unreach.c
+++ b/bgpd/bgp_unreach.c
@@ -1074,7 +1074,7 @@ static void bgp_unreach_path_detail_json(json_object *json_path,
if (comm) {
if (!comm->json)
- community_str(comm, true, true);
+ community_str(comm, true);
json_object_lock(comm->json);
json_object_object_add(json_path, "community",
comm->json);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index bb37bae3f1..f42134670a 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -13786,13 +13786,13 @@ static void bgp_show_aggregate_one(struct vty *vty, const struct prefix *p,
aggregate->suppress_map_name);
if (aggregate->community)
json_object_string_add(json_aggr, "community",
- community_str(aggregate->community, false, false));
+ community_str(aggregate->community, false));
if (aggregate->ecommunity)
json_object_string_add(json_aggr, "extendedCommunity",
ecommunity_str(aggregate->ecommunity));
if (aggregate->lcommunity)
json_object_string_add(json_aggr, "largeCommunity",
- lcommunity_str(aggregate->lcommunity, false, false));
+ lcommunity_str(aggregate->lcommunity, false));
if (aggregate->aspath)
json_object_string_add(json_aggr, "asPath",
aspath_print(aggregate->aspath));
@@ -13822,13 +13822,13 @@ static void bgp_show_aggregate_one(struct vty *vty, const struct prefix *p,
vty_out(vty, " Suppress-map: %s\n", aggregate->suppress_map_name);
if (aggregate->community)
vty_out(vty, " Community: %s\n",
- community_str(aggregate->community, false, false));
+ community_str(aggregate->community, false));
if (aggregate->ecommunity)
vty_out(vty, " Extended community: %s\n",
ecommunity_str(aggregate->ecommunity));
if (aggregate->lcommunity)
vty_out(vty, " Large community: %s\n",
- lcommunity_str(aggregate->lcommunity, false, false));
+ lcommunity_str(aggregate->lcommunity, false));
if (aggregate->aspath)
vty_out(vty, " AS path: %s\n", aspath_print(aggregate->aspath));
}
@@ -19085,8 +19085,7 @@ static void community_show_all_iterator(struct hash_bucket *bucket,
struct community *com;
com = (struct community *)bucket->data;
- vty_out(vty, "[%p] (%ld) %s\n", (void *)com, com->refcnt,
- community_str(com, false, false));
+ vty_out(vty, "[%p] (%ld) %s\n", (void *)com, com->refcnt, community_str(com, false));
}
/* Show BGP's community internal data. */
@@ -19114,8 +19113,7 @@ static void lcommunity_show_all_iterator(struct hash_bucket *bucket,
struct lcommunity *lcom;
lcom = (struct lcommunity *)bucket->data;
- vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt,
- lcommunity_str(lcom, false, false));
+ vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt, lcommunity_str(lcom, false));
}
/* Show BGP's community internal data. */
@@ -25613,9 +25611,9 @@ static const char *community_list_config_str(struct community_entry *entry)
const char *str;
if (entry->style == COMMUNITY_LIST_STANDARD)
- str = community_str(entry->u.com, false, false);
+ str = community_str(entry->u.com, false);
else if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
- str = lcommunity_str(entry->u.lcom, false, false);
+ str = lcommunity_str(entry->u.lcom, false);
else
str = entry->config;
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 22dc36d622..5aac3a911a 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -55,6 +55,7 @@
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_srv6.h"
#include "bgpd/bgp_ls.h"
#include "bgpd/bgp_ls_ted.h"
@@ -1664,15 +1665,21 @@ enum zclient_send_status bgp_zebra_announce_actual(struct bgp_dest *dest,
strlcpy(bzo.aspath, info->attr->aspath->str,
sizeof(bzo.aspath));
- if (bgp_attr_exists(info->attr, BGP_ATTR_COMMUNITIES))
- strlcpy(bzo.community,
- bgp_attr_get_community(info->attr)->str,
- sizeof(bzo.community));
+ if (bgp_attr_exists(info->attr, BGP_ATTR_COMMUNITIES)) {
+ char *str =
+ bgp_community2alias_str(bgp_attr_get_community(info->attr)->str);
- if (bgp_attr_exists(info->attr, BGP_ATTR_LARGE_COMMUNITIES))
- strlcpy(bzo.lcommunity,
- bgp_attr_get_lcommunity(info->attr)->str,
- sizeof(bzo.lcommunity));
+ strlcpy(bzo.community, str, sizeof(bzo.community));
+ XFREE(MTYPE_TMP, str);
+ }
+
+ if (bgp_attr_exists(info->attr, BGP_ATTR_LARGE_COMMUNITIES)) {
+ char *str =
+ bgp_community2alias_str(bgp_attr_get_lcommunity(info->attr)->str);
+
+ strlcpy(bzo.lcommunity, str, sizeof(bzo.lcommunity));
+ XFREE(MTYPE_TMP, str);
+ }
strlcpy(bzo.selection_reason, reason,
sizeof(bzo.selection_reason));
diff --git a/tests/bgpd/test_community.c b/tests/bgpd/test_community.c
index 7aed4f237a..164cf964f1 100644
--- a/tests/bgpd/test_community.c
+++ b/tests/bgpd/test_community.c
@@ -56,7 +56,7 @@ static void test_large_community_not_truncated(void)
com = community_str2com(input);
assert(com);
- str = community_str(com, false, false);
+ str = community_str(com, false);
printf("rendered string length: %zu (%d communities)\n", strlen(str),
com->size);