Commit bd33f1cca7 for frr

commit bd33f1cca7d0fa3357bcf3bc1e4853fa9a98eac3
Author: Srinivasan Koona Lokabiraman <srinivasan@nexthop.ai>
Date:   Fri Oct 23 05:34:38 2026 +0000

    bgpd: make color extcommunity config output re-enterable

    The color extended-community formatter ignores the 'format' argument
    and always emits the ECOMMUNITY_FORMAT_DISPLAY spelling
    (Color:CC:VALUE), including when rendering re-parseable config.

      bgp extcommunity-list standard TEST permit color 00:100

    is written back to running-config as 'permit Color:00:100', which the
    parser rejects with '% Malformed community-list value', because
    ecommunity_gettoken() requires the color keyword to be followed by
    whitespace, not ':'. Pasting back a saved running-config therefore
    loses the extcommunity-list entry.

    Branch on the format, as ecommunity_rt_soo_str_internal() does. Unlike
    rt/soo, no caller prints a 'color' keyword ahead of the value, so both
    re-parseable formats carry the keyword themselves. Display output is
    unchanged.

    Signed-off-by: Srinivasan Koona Lokabiraman <srinivasan@nexthop.ai>

diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 6e035b7ea1..6897096fcf 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -422,7 +422,23 @@ bool ecommunity_cmp(const void *arg1, const void *arg2)
 			  ecom1->unit_size) == 0);
 }

-static void ecommunity_color_str(char *buf, size_t bufsz, uint8_t *ptr)
+/* Unlike rt/soo, no caller emits a "color" keyword ahead of the value, so
+ * the re-parseable formats have to carry it themselves.
+ */
+static const char *ecommunity_color_prefix(int format)
+{
+	switch (format) {
+	case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
+	case ECOMMUNITY_FORMAT_ROUTE_MAP:
+		return "color ";
+	case ECOMMUNITY_FORMAT_DISPLAY:
+	default:
+		return "Color:";
+	}
+}
+
+static void ecommunity_color_str(char *buf, size_t bufsz, uint8_t *ptr,
+				 int format)
 {
 	/*
 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -441,7 +457,8 @@ static void ecommunity_color_str(char *buf, size_t bufsz, uint8_t *ptr)

 	memcpy(&colorid, ptr + 2, 4);
 	colorid = ntohl(colorid);
-	snprintf(buf, bufsz, "Color:%d%d:%d", (color_type & 0x2) >> 1, color_type & 0x1, colorid);
+	snprintfrr(buf, bufsz, "%s%d%d:%u", ecommunity_color_prefix(format),
+		   (color_type & 0x2) >> 1, color_type & 0x1, colorid);
 }

 /* Initialize Extended Comminities related hash. */
@@ -1350,7 +1367,7 @@ static char *_ecommunity_ecom2str(struct ecommunity *ecom, int format, int filte
 					sizeof(encbuf));
 			} else if (*pnt == ECOMMUNITY_COLOR) {
 				ecommunity_color_str(encbuf, sizeof(encbuf),
-						     pnt);
+						     pnt, format);
 			} else if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_UPA) {
 				struct in_addr rid = {};
 				uint8_t flags = data[BGP_UPA_EXTCOM_OFF_FLAGS];