diff options
Diffstat (limited to 'bgpd')
| -rw-r--r-- | bgpd/bgp_routemap.c | 76 | ||||
| -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 | 51 | 
4 files changed, 138 insertions, 0 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d8d1fa5ddc..fa8701dc50 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1303,6 +1303,61 @@ static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {  	route_match_rd_free  }; +/* `match community-limit' */ + +/* Match function should return : + * - RMAP_MATCH if the bgp update community list count + * is less or equal to the configured limit. + * - RMAP_NOMATCH if the community list count is greater than the + * configured limit. + */ +static enum route_map_cmd_result_t +route_match_community_limit(void *rule, const struct prefix *prefix, void *object) +{ +	struct bgp_path_info *path = NULL; +	struct community *picomm = NULL; +	uint16_t count = 0; +	uint16_t *limit_rule = rule; + +	path = (struct bgp_path_info *)object; + +	picomm = bgp_attr_get_community(path->attr); +	if (picomm) +		count = picomm->size; + +	if (count <= *limit_rule) +		return RMAP_MATCH; + +	return RMAP_NOMATCH; +} + +/* Route map `community-limit' match statement. */ +static void *route_match_community_limit_compile(const char *arg) +{ +	uint16_t *limit = NULL; +	char *end = NULL; + +	limit = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint16_t)); +	*limit = strtoul(arg, &end, 10); +	if (*end != '\0') { +		XFREE(MTYPE_ROUTE_MAP_COMPILED, limit); +		return NULL; +	} +	return limit; +} + +/* Free route map's compiled `community-limit' value. */ +static void route_match_community_limit_free(void *rule) +{ +	XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for community limit matching. */ +static const struct route_map_rule_cmd route_match_community_limit_cmd = { +	"community-limit", route_match_community_limit, +	route_match_community_limit_compile, route_match_community_limit_free +}; +  static enum route_map_cmd_result_t  route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)  { @@ -5707,6 +5762,25 @@ DEFPY_YANG(  	return nb_cli_apply_changes(vty, NULL);  } +DEFPY_YANG( +	match_community_limit, match_community_limit_cmd, +	"[no$no] match community-limit ![(0-65535)$limit]", +	NO_STR +	MATCH_STR +	"Match BGP community limit\n" +	"Community limit number\n") +{ +	const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community-limit']"; +	char xpath_value[XPATH_MAXLEN]; + +	nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, NULL); +	snprintf(xpath_value, sizeof(xpath_value), +		 "%s/rmap-match-condition/frr-bgp-route-map:community-limit", xpath); + +	nb_cli_enqueue_change(vty, xpath_value, no ? NB_OP_DESTROY : NB_OP_MODIFY, limit_str); +	return nb_cli_apply_changes(vty, NULL); +} +  DEFUN_YANG(  	no_match_community, no_match_community_cmd,  	"no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]", @@ -7905,6 +7979,7 @@ void bgp_route_map_init(void)  	route_map_install_match(&route_match_evpn_vni_cmd);  	route_map_install_match(&route_match_evpn_route_type_cmd);  	route_map_install_match(&route_match_evpn_rd_cmd); +	route_map_install_match(&route_match_community_limit_cmd);  	route_map_install_match(&route_match_evpn_default_route_cmd);  	route_map_install_match(&route_match_vrl_source_vrf_cmd); @@ -7977,6 +8052,7 @@ void bgp_route_map_init(void)  	install_element(RMAP_NODE, &no_match_alias_cmd);  	install_element(RMAP_NODE, &match_community_cmd);  	install_element(RMAP_NODE, &no_match_community_cmd); +	install_element(RMAP_NODE, &match_community_limit_cmd);  	install_element(RMAP_NODE, &match_lcommunity_cmd);  	install_element(RMAP_NODE, &no_match_lcommunity_cmd);  	install_element(RMAP_NODE, &match_ecommunity_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index d8fdb4fbc4..4645593441 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -166,6 +166,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {  			}  		},  		{ +			.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:community-limit", +			.cbs = { +				.modify = lib_route_map_entry_match_condition_rmap_match_condition_community_limit_modify, +				.destroy = lib_route_map_entry_match_condition_rmap_match_condition_community_limit_destroy, +			} +		}, +		{  			.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list",  			.cbs = {  				.create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create, diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index f59686f386..45689242a0 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -72,6 +72,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod  int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args);  int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args);  int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_modify( +	struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_destroy( +	struct nb_cb_destroy_args *args);  int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(  	struct nb_cb_create_args *args);  int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 0dca196ed6..223c416dc5 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -1275,6 +1275,57 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des  }  /* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:community-limit + */ +int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_modify( +	struct nb_cb_modify_args *args) +{ +	struct routemap_hook_context *rhc; +	const char *limit; +	enum rmap_compile_rets ret; + +	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); +		limit = yang_dnode_get_string(args->dnode, NULL); + +		rhc->rhc_mhook = bgp_route_match_delete; +		rhc->rhc_rule = "community-limit"; +		rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + +		ret = bgp_route_match_add(rhc->rhc_rmi, "community-limit", limit, +					  RMAP_EVENT_MATCH_ADDED, args->errmsg, args->errmsg_len); + +		if (ret != RMAP_COMPILE_SUCCESS) { +			rhc->rhc_mhook = NULL; +			return NB_ERR_INCONSISTENCY; +		} +	} + +	return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_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/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list   */  int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(  | 
