diff options
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 97 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 33 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 93 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb.c | 7 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb_config.c | 52 | ||||
| -rw-r--r-- | lib/routemap.h | 3 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 5 | ||||
| -rw-r--r-- | yang/frr-bgp-route-map.yang | 35 | 
9 files changed, 313 insertions, 16 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index a555930137..ec860c5a1c 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -355,6 +355,22 @@ 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) +{ +	/* +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 *  | 0x03         | Sub-Type(0x0b) |    Flags                      | +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 *  |                          Color Value                          | +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 */ +	uint32_t colorid; + +	memcpy(&colorid, ptr + 3, 4); +	colorid = ntohl(colorid); +	snprintf(buf, bufsz, "Color:%d", colorid); +} +  /* Initialize Extended Comminities related hash. */  void ecommunity_init(void)  { @@ -373,6 +389,7 @@ enum ecommunity_token {  	ecommunity_token_rt,  	ecommunity_token_nt,  	ecommunity_token_soo, +	ecommunity_token_color,  	ecommunity_token_val,  	ecommunity_token_rt6,  	ecommunity_token_val6, @@ -510,6 +527,9 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,  		memcpy(&eval6->val[2], ip6, sizeof(struct in6_addr));  		eval6->val[18] = (val >> 8) & 0xff;  		eval6->val[19] = val & 0xff; +	} else if (type == ECOMMUNITY_ENCODE_OPAQUE && +		   sub_type == ECOMMUNITY_COLOR) { +		encode_color(val, eval);  	} else {  		encode_route_target_as4(as, val, eval, trans);  	} @@ -537,16 +557,22 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,  	int dot = 0;  	int digit = 0;  	int separator = 0; +	int i;  	const char *p = str;  	char *endptr;  	struct in_addr ip;  	struct in6_addr ip6;  	as_t as = 0;  	uint32_t val = 0; -	uint8_t ecomm_type; +	uint32_t val_color = 0; +	uint8_t ecomm_type = 0; +	uint8_t sub_type = 0;  	char buf[INET_ADDRSTRLEN + 1];  	struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr;  	uint64_t tmp_as = 0; +	static const char str_color[5] = "color"; +	const char *ptr_color; +	bool val_color_set = false;  	/* Skip white space. */  	while (isspace((unsigned char)*p)) { @@ -558,7 +584,7 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,  	if (*p == '\0')  		return NULL; -	/* "rt", "nt", and "soo" keyword parse. */ +	/* "rt", "nt", "soo", and "color" keyword parse. */  	if (!isdigit((unsigned char)*p)) {  		/* "rt" match check.  */  		if (tolower((unsigned char)*p) == 'r') { @@ -612,10 +638,33 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,  				return p;  			}  			goto error; +		} else if (tolower((unsigned char)*p) == 'c') { +			/* "color" match check. +			 * 'c', 'co', 'col', 'colo' are also accepted +			 */ +			for (i = 0; i < 5; i++) { +				ptr_color = &str_color[0]; +				if (tolower((unsigned char)*p) == *ptr_color) { +					p++; +					ptr_color++; +				} else if (i > 0) { +					if (isspace((unsigned char)*p) || +					    *p == '\0') { +						*token = ecommunity_token_color; +						return p; +					} +					goto error; +				} +				if (isspace((unsigned char)*p) || *p == '\0') { +					*token = ecommunity_token_color; +					return p; +				} +				goto error; +			} +			goto error;  		}  		goto error;  	} -  	/* What a mess, there are several possibilities:  	 *  	 * a) A.B.C.D:MN @@ -716,17 +765,24 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,  		} else {  			digit = 1; -			/* We're past the IP/ASN part */ +			/* We're past the IP/ASN part, +			 * or we have a color +			 */  			if (separator) {  				val *= 10;  				val += (*p - '0'); +				val_color_set = false; +			} else { +				val_color *= 10; +				val_color += (*p - '0'); +				val_color_set = true;  			}  		}  		p++;  	}  	/* Low digit part must be there. */ -	if (!digit || !separator) +	if (!digit && (!separator || !val_color_set))  		goto error;  	/* Encode result into extended community.  */ @@ -734,9 +790,15 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,  		ecomm_type = ECOMMUNITY_ENCODE_IP;  	else if (as > BGP_AS_MAX)  		ecomm_type = ECOMMUNITY_ENCODE_AS4; -	else +	else if (as > 0)  		ecomm_type = ECOMMUNITY_ENCODE_AS; -	if (ecommunity_encode(ecomm_type, type, 1, as, ip, val, eval)) +	else if (val_color) { +		ecomm_type = ECOMMUNITY_ENCODE_OPAQUE; +		sub_type = ECOMMUNITY_COLOR; +		val = val_color; +	} + +	if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval))  		goto error;  	*token = ecommunity_token_val;  	return p; @@ -763,6 +825,7 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,  		case ecommunity_token_nt:  		case ecommunity_token_rt6:  		case ecommunity_token_soo: +		case ecommunity_token_color:  			if (!keyword_included || keyword) {  				if (ecom)  					ecommunity_free(&ecom); @@ -771,15 +834,14 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,  			keyword = 1;  			if (token == ecommunity_token_rt || -			    token == ecommunity_token_rt6) { +			    token == ecommunity_token_rt6)  				type = ECOMMUNITY_ROUTE_TARGET; -			} -			if (token == ecommunity_token_soo) { +			if (token == ecommunity_token_soo)  				type = ECOMMUNITY_SITE_ORIGIN; -			} -			if (token == ecommunity_token_nt) { +			if (token == ecommunity_token_nt)  				type = ECOMMUNITY_NODE_TARGET; -			} +			if (token == ecommunity_token_color) +				type = ECOMMUNITY_COLOR;  			break;  		case ecommunity_token_val:  			if (keyword_included) { @@ -998,10 +1060,12 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,  	"rt 100:1 100:2soo 100:3"     extcommunity-list -	"rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching +	"rt 100:1 rt 100:2 soo 100:3 +	show [ip] bgp" +   and extcommunity-list regular expression matching  	"RT:100:1 RT:100:2 SoO:100:3" -   For each formath please use below definition for format: +   For each format please use below definition for format:     ECOMMUNITY_FORMAT_ROUTE_MAP     ECOMMUNITY_FORMAT_COMMUNITY_LIST @@ -1086,6 +1150,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)  			} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {  				strlcpy(encbuf, "Default Gateway",  					sizeof(encbuf)); +			} else if (*pnt == ECOMMUNITY_COLOR) { +				ecommunity_color_str(encbuf, sizeof(encbuf), +						     pnt);  			} else {  				unk_ecom = 1;  			} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 94a178bbb6..5e67e5015e 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -46,6 +46,8 @@  #define ECOMMUNITY_REDIRECT_VRF             0x08  #define ECOMMUNITY_TRAFFIC_MARKING          0x09  #define ECOMMUNITY_REDIRECT_IP_NH           0x00 +#define ECOMMUNITY_COLOR 0x0b /* RFC9012 - color */ +  /* from IANA: bgp-extended-communities/bgp-extended-communities.xhtml   * 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect   */ @@ -290,6 +292,35 @@ static inline void encode_node_target(struct in_addr *node_id,  	eval->val[7] = ECOMMUNITY_NODE_TARGET_RESERVED;  } +/* + * Encode BGP Color extended community + * is's a transitive opaque Extended community (RFC 9012 4.3) + * flag is set to 0 + * RFC 9012 14.10: No values have currently been registered. + *            4.3: this field MUST be set to zero by the originator + *                 and ignored by the receiver; + * + */ +static inline void encode_color(uint32_t color_id, struct ecommunity_val *eval) +{ +	/* +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 *  | 0x03         | Sub-Type(0x0b) |    Flags                      | +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 *  |                          Color Value                          | +	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +	 */ +	memset(eval, 0, sizeof(*eval)); +	eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE; +	eval->val[1] = ECOMMUNITY_COLOR; +	eval->val[2] = 0x00; +	eval->val[3] = 0x00; +	eval->val[4] = (color_id >> 24) & 0xff; +	eval->val[5] = (color_id >> 16) & 0xff; +	eval->val[6] = (color_id >> 8) & 0xff; +	eval->val[7] = color_id & 0xff; +} +  extern void ecommunity_init(void);  extern void ecommunity_finish(void);  extern void ecommunity_free(struct ecommunity **); @@ -314,7 +345,7 @@ extern void ecommunity_strfree(char **s);  extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);  extern bool ecommunity_match(const struct ecommunity *,  			     const struct ecommunity *); -extern char *ecommunity_str(struct ecommunity *); +extern char *ecommunity_str(struct ecommunity *ecom);  extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,  						uint8_t, uint8_t); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 7db110be93..c5de9928a7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3055,6 +3055,44 @@ static void *route_set_ecommunity_lb_compile(const char *arg)  	return rels;  } +static enum route_map_cmd_result_t +route_set_ecommunity_color(void *rule, const struct prefix *prefix, +			   void *object) +{ +	struct bgp_path_info *path; + +	path = object; + +	route_set_ecommunity(rule, prefix, object); + +	path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); +	return RMAP_OKAY; +} + +static void *route_set_ecommunity_color_compile(const char *arg) +{ +	struct rmap_ecom_set *rcs; +	struct ecommunity *ecom; + +	ecom = ecommunity_str2com(arg, ECOMMUNITY_COLOR, 0); +	if (!ecom) +		return NULL; + +	rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_ecom_set)); +	rcs->ecom = ecommunity_intern(ecom); +	rcs->none = false; + +	return rcs; +} + +static const struct route_map_rule_cmd route_set_ecommunity_color_cmd = { +	"extcommunity color", +	route_set_ecommunity_color, +	route_set_ecommunity_color_compile, +	route_set_ecommunity_free, +}; + +  static void route_set_ecommunity_lb_free(void *rule)  {  	XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); @@ -6522,6 +6560,57 @@ DEFPY_YANG (no_set_ecommunity_nt,  	return nb_cli_apply_changes(vty, NULL);  } +DEFPY_YANG(set_ecommunity_color, set_ecommunity_color_cmd, +	   "set extcommunity color RTLIST...", +	   SET_STR +	   "BGP extended community attribute\n" +	   "Color extended community\n" +	   "Color ID\n") +{ +	int idx_color = 3; +	char *str; +	int ret; +	const char *xpath = +		"./set-action[action='frr-bgp-route-map:set-extcommunity-color']"; +	char xpath_value[XPATH_MAXLEN]; + +	nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + +	snprintf(xpath_value, sizeof(xpath_value), +		 "%s/rmap-set-action/frr-bgp-route-map:extcommunity-color", +		 xpath); +	str = argv_concat(argv, argc, idx_color); +	nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); +	ret = nb_cli_apply_changes(vty, NULL); +	XFREE(MTYPE_TMP, str); +	return ret; +} + +DEFPY_YANG(no_set_ecommunity_color_all, no_set_ecommunity_color_all_cmd, +	   "no set extcommunity color", +	   NO_STR SET_STR +	   "BGP extended community attribute\n" +	   "Color extended community\n") +{ +	const char *xpath = +		"./set-action[action='frr-bgp-route-map:set-extcommunity-color']"; +	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); +	return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(no_set_ecommunity_color, no_set_ecommunity_color_cmd, +	   "no set extcommunity color RTLIST...", +	   NO_STR SET_STR +	   "BGP extended community attribute\n" +	   "Color extended community\n" +	   "Color ID\n") +{ +	const char *xpath = +		"./set-action[action='frr-bgp-route-map:set-extcommunity-color']"; +	nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); +	return nb_cli_apply_changes(vty, NULL); +} +  ALIAS_YANG (no_set_ecommunity_nt,              no_set_ecommunity_nt_short_cmd,              "no set extcommunity nt", @@ -7375,6 +7464,7 @@ void bgp_route_map_init(void)  	route_map_install_set(&route_set_ecommunity_nt_cmd);  	route_map_install_set(&route_set_ecommunity_soo_cmd);  	route_map_install_set(&route_set_ecommunity_lb_cmd); +	route_map_install_set(&route_set_ecommunity_color_cmd);  	route_map_install_set(&route_set_ecommunity_none_cmd);  	route_map_install_set(&route_set_tag_cmd);  	route_map_install_set(&route_set_label_index_cmd); @@ -7478,6 +7568,9 @@ void bgp_route_map_init(void)  	install_element(RMAP_NODE, &set_ecommunity_nt_cmd);  	install_element(RMAP_NODE, &no_set_ecommunity_nt_cmd);  	install_element(RMAP_NODE, &no_set_ecommunity_nt_short_cmd); +	install_element(RMAP_NODE, &set_ecommunity_color_cmd); +	install_element(RMAP_NODE, &no_set_ecommunity_color_cmd); +	install_element(RMAP_NODE, &no_set_ecommunity_color_all_cmd);  #ifdef KEEP_OLD_VPN_COMMANDS  	install_element(RMAP_NODE, &set_vpn_nexthop_cmd);  	install_element(RMAP_NODE, &no_set_vpn_nexthop_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 282ebe9116..ae695a6f80 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -401,6 +401,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {  			}  		},  		{ +			.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-color", +			.cbs = { +				.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_modify, +				.destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_destroy, +			} +		}, +		{  			.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific",  			.cbs = {  				.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify, diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 7066fdb419..3ff58f71a7 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -153,6 +153,10 @@ int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(  	struct nb_cb_modify_args *args);  int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(  	struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_modify( +	struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_destroy( +	struct nb_cb_destroy_args *args);  int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_modify(  	struct nb_cb_modify_args *args);  int lib_route_map_entry_set_action_rmap_set_action_l3vpn_nexthop_encapsulation_destroy( diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 02564b0004..03b588a33b 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -2954,6 +2954,58 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy  /*   * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-color + */ +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_modify( +	struct nb_cb_modify_args *args) +{ +	struct routemap_hook_context *rhc; +	const char *str; +	int rv; + +	switch (args->event) { +	case NB_EV_VALIDATE: +	case NB_EV_PREPARE: +	case NB_EV_ABORT: +		break; +	case NB_EV_APPLY: +		/* Add configuration. */ +		rhc = nb_running_get_entry(args->dnode, NULL, true); +		str = yang_dnode_get_string(args->dnode, NULL); + +		/* Set destroy information. */ +		rhc->rhc_shook = generic_set_delete; +		rhc->rhc_rule = "extcommunity color"; +		rhc->rhc_event = RMAP_EVENT_SET_DELETED; + +		rv = generic_set_add(rhc->rhc_rmi, "extcommunity color", str, +				     args->errmsg, args->errmsg_len); +		if (rv != CMD_SUCCESS) { +			rhc->rhc_shook = NULL; +			return NB_ERR_INCONSISTENCY; +		} +	} + +	return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_destroy( +	struct nb_cb_destroy_args *args) +{ +	switch (args->event) { +	case NB_EV_VALIDATE: +	case NB_EV_PREPARE: +	case NB_EV_ABORT: +		break; +	case NB_EV_APPLY: +		return lib_route_map_entry_match_destroy(args); +	} + +	return NB_OK; +} + +/* + * XPath:   * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific   */  int diff --git a/lib/routemap.h b/lib/routemap.h index 7277744dc5..a83ef9c967 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -362,6 +362,9 @@ DECLARE_QOBJ_TYPE(route_map);  	(strmatch(A, "frr-bgp-route-map:set-extcommunity-soo"))  #define IS_SET_EXTCOMMUNITY_LB(A)                                              \  	(strmatch(A, "frr-bgp-route-map:set-extcommunity-lb")) +#define IS_SET_EXTCOMMUNITY_COLOR(A)                                           \ +	(strmatch(A, "frr-bgp-route-map:set-extcommunity-color")) +  #define IS_SET_AGGREGATOR(A)                                                   \  	(strmatch(A, "frr-bgp-route-map:aggregator"))  #define IS_SET_AS_PREPEND(A)                                                   \ diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 0ccc78e838..c1bdd28eab 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -1259,6 +1259,11 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,  			strlcat(str, " non-transitive", sizeof(str));  		vty_out(vty, " set extcommunity bandwidth %s\n", str); +	} else if (IS_SET_EXTCOMMUNITY_COLOR(action)) { +		vty_out(vty, " set extcommunity color %s\n", +			yang_dnode_get_string( +				dnode, +				"./rmap-set-action/frr-bgp-route-map:extcommunity-color"));  	} else if (IS_SET_EXTCOMMUNITY_NONE(action)) {  		if (yang_dnode_get_bool(  			    dnode, diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index b557cabb22..4b6619739d 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -214,6 +214,12 @@ module frr-bgp-route-map {        "Set BGP extended community attribute";    } +identity set-extcommunity-color { +    base frr-route-map:rmap-set-type; +    description +      "Set BGP extended community attribute"; +  } +    identity set-ipv4-nexthop {      base frr-route-map:rmap-set-type;      description @@ -511,6 +517,22 @@ module frr-bgp-route-map {      }    } +  typedef color-list { +    type string { +      pattern '((429496729[0-5]|42949672[0-8][0-9]|' +      +	    '4294967[0-1][0-9]{2}|429496[0-6][0-9]{3}|' +      +	    '42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|' +      +	    '429[0-3][0-9]{6}|42[0-8][0-9]{7}|' +      +	    '4[0-1][0-9]{8}|[1-3][0-9]{9}|' +      +	    '[1-9][0-9]{0,8})(\s*))+'; +    } +    description +      "The color-list type represent a set of colors of value (1..4294967295) +       values are separated by white spaces"; +    reference +      "RFC 9012 - The BGP Tunnel Encapsulation Attribute"; +  } +    augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:rmap-match-condition/frr-route-map:match-condition" {      case local-preference {        when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-local-preference')"; @@ -852,6 +874,19 @@ module frr-bgp-route-map {        }      } +   case extcommunity-color { +      when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-color')"; +      description +        "Value of the ext-community"; +      leaf extcommunity-color { +        type color-list; +        description +          "Set BGP ext-community color attribute with a list of colors"; +	reference +	  "RFC9012"; +      } +    } +      case ipv4-address {        when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv4-vpn-address')";        description  | 
