diff options
| author | Donatas Abraitis <donatas@opensourcerouting.org> | 2022-10-18 14:17:04 +0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-18 14:17:04 +0300 | 
| commit | 272c6d5db128ff7450fe9fcd16c046160594deb3 (patch) | |
| tree | 83cf59443f6641c80260a0e75aded8211478bc34 /bgpd/bgp_evpn_vty.c | |
| parent | a654221c7083dd27741b48f3167ca49c3c51048c (diff) | |
| parent | a5d7012ca0c04c97bd15b67e9f6e9211203b7c31 (diff) | |
Merge pull request #8647 from sworleys/DVNI-Config-Changes
bgpd: EVPN D-VNI L3 RT Config Enhancements
Diffstat (limited to 'bgpd/bgp_evpn_vty.c')
| -rw-r--r-- | bgpd/bgp_evpn_vty.c | 425 | 
1 files changed, 324 insertions, 101 deletions
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 5ad5cf8bff..f920a783b3 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -373,7 +373,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,  	char buf1[INET6_ADDRSTRLEN];  	char *ecom_str;  	struct listnode *node, *nnode; -	struct ecommunity *ecom; +	struct vrf_route_target *l3rt;  	json_object *json_import_rtl = NULL;  	json_object *json_export_rtl = NULL;  	char buf2[ETHER_ADDR_STRLEN]; @@ -431,8 +431,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,  	if (!json)  		vty_out(vty, "  Import Route Target:\n"); -	for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) { -		ecom_str = ecommunity_ecom2str(ecom, +	for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt)) { +		ecom_str = ecommunity_ecom2str(l3rt->ecom,  					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);  		if (json) @@ -449,8 +449,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,  	else  		vty_out(vty, "  Export Route Target:\n"); -	for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) { -		ecom_str = ecommunity_ecom2str(ecom, +	for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, l3rt)) { +		ecom_str = ecommunity_ecom2str(l3rt->ecom,  					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);  		if (json) @@ -913,7 +913,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,  	char rt_buf[25];  	char *ecom_str;  	struct listnode *node, *nnode; -	struct ecommunity *ecom; +	struct vrf_route_target *l3rt;  	if (!bgp->l3vni)  		return; @@ -954,8 +954,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,  			&bgp->vrf_prd);  	} -	for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) { -		ecom_str = ecommunity_ecom2str(ecom, +	for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, l3rt)) { +		ecom_str = ecommunity_ecom2str(l3rt->ecom,  					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);  		if (json) { @@ -982,8 +982,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,  	if (json)  		json_object_object_add(json_vni, "importRTs", json_import_rtl); -	for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) { -		ecom_str = ecommunity_ecom2str(ecom, +	for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, l3rt)) { +		ecom_str = ecommunity_ecom2str(l3rt->ecom,  					       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);  		if (json) { @@ -1984,12 +1984,12 @@ DEFUN(no_evpnrt5_network,  static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)  { -	evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl); +	evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl, false);  }  static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)  { -	evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl); +	evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl, false);  }  /* @@ -3980,11 +3980,13 @@ DEFUN (bgp_evpn_advertise_type5,  DEFUN (no_bgp_evpn_advertise_type5,         no_bgp_evpn_advertise_type5_cmd, -       "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR, +       "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",         NO_STR         "Advertise prefix routes\n"         BGP_AFI_HELP_STR -       BGP_SAFI_HELP_STR) +       BGP_SAFI_HELP_STR +       "route-map for filtering specific routes\n" +       "Name of the route map\n")  {  	struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */  	int idx_afi = 0; @@ -5654,18 +5656,35 @@ DEFUN (no_bgp_evpn_vni_rd_without_val,   * Loop over all extended-communities in the route-target list rtl and   * return 1 if we find ecomtarget   */ -static int bgp_evpn_rt_matches_existing(struct list *rtl, -					struct ecommunity *ecomtarget) +static bool bgp_evpn_rt_matches_existing(struct list *rtl, +					 struct ecommunity *ecomtarget)  { -	struct listnode *node, *nnode; +	struct listnode *node;  	struct ecommunity *ecom; -	for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) { +	for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom)) {  		if (ecommunity_match(ecom, ecomtarget)) -			return 1; +			return true;  	} -	return 0; +	return false; +} + +/* + * L3 RT version of above. + */ +static bool bgp_evpn_vrf_rt_matches_existing(struct list *rtl, +					     struct ecommunity *ecomtarget) +{ +	struct listnode *node; +	struct vrf_route_target *l3rt; + +	for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt)) { +		if (ecommunity_match(l3rt->ecom, ecomtarget)) +			return true; +	} + +	return false;  }  /* display L3VNI related info for a VRF instance */ @@ -5685,7 +5704,7 @@ DEFUN (show_bgp_vrf_l3vni_info,  	struct bgp *bgp = NULL;  	struct listnode *node = NULL;  	struct bgpevpn *vpn = NULL; -	struct ecommunity *ecom = NULL; +	struct vrf_route_target *l3rt;  	json_object *json = NULL;  	json_object *json_vnis = NULL;  	json_object *json_export_rts = NULL; @@ -5735,13 +5754,13 @@ DEFUN (show_bgp_vrf_l3vni_info,  		vty_out(vty, "\n");  		vty_out(vty, "  Export-RTs:\n");  		vty_out(vty, "    "); -		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom)) -			vty_out(vty, "%s  ", ecommunity_str(ecom)); +		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, l3rt)) +			vty_out(vty, "%s  ", ecommunity_str(l3rt->ecom));  		vty_out(vty, "\n");  		vty_out(vty, "  Import-RTs:\n");  		vty_out(vty, "    "); -		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom)) -			vty_out(vty, "%s  ", ecommunity_str(ecom)); +		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, l3rt)) +			vty_out(vty, "%s  ", ecommunity_str(l3rt->ecom));  		vty_out(vty, "\n");  		vty_out(vty, "  RD: %pRD\n", &bgp->vrf_prd);  	} else { @@ -5765,17 +5784,19 @@ DEFUN (show_bgp_vrf_l3vni_info,  		json_object_object_add(json, "l2vnis", json_vnis);  		/* export rts */ -		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom)) +		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, l3rt))  			json_object_array_add(  				json_export_rts, -				json_object_new_string(ecommunity_str(ecom))); +				json_object_new_string( +					ecommunity_str(l3rt->ecom)));  		json_object_object_add(json, "export-rts", json_export_rts);  		/* import rts */ -		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom)) +		for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, l3rt))  			json_object_array_add(  				json_import_rts, -				json_object_new_string(ecommunity_str(ecom))); +				json_object_new_string( +					ecommunity_str(l3rt->ecom)));  		json_object_object_add(json, "import-rts", json_import_rts);  		json_object_string_addf(json, "rd", "%pRD", &bgp->vrf_prd);  	} @@ -5785,22 +5806,133 @@ DEFUN (show_bgp_vrf_l3vni_info,  	return CMD_SUCCESS;  } +static int add_rt(struct bgp *bgp, struct ecommunity *ecom, bool is_import, +		  bool is_wildcard) +{ +	/* Do nothing if we already have this route-target */ +	if (is_import) { +		if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_import_rtl, +						      ecom)) +			bgp_evpn_configure_import_rt_for_vrf(bgp, ecom, +							     is_wildcard); +		else +			return -1; +	} else { +		if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_export_rtl, +						      ecom)) +			bgp_evpn_configure_export_rt_for_vrf(bgp, ecom); +		else +			return -1; +	} + +	return 0; +} + +static int del_rt(struct bgp *bgp, struct ecommunity *ecom, bool is_import) +{ +	/* Verify we already have this route-target */ +	if (is_import) { +		if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_import_rtl, +						      ecom)) +			return -1; + +		bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecom); +	} else { +		if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_export_rtl, +						      ecom)) +			return -1; + +		bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecom); +	} + +	return 0; +} + +static int parse_rtlist(struct bgp *bgp, struct vty *vty, int argc, +			struct cmd_token **argv, int rt_idx, bool is_add, +			bool is_import) +{ +	int ret = CMD_SUCCESS; +	bool is_wildcard = false; +	struct ecommunity *ecom = NULL; + +	for (int i = rt_idx; i < argc; i++) { +		is_wildcard = false; + +		/* +		 * Special handling for wildcard '*' here. +		 * +		 * Let's just convert it to 0 here so we dont have to modify +		 * the ecommunity parser. +		 */ +		if ((argv[i]->arg)[0] == '*') { +			if (!is_import) { +				vty_out(vty, +					"%% Wildcard '*' only applicable for import\n"); +				ret = CMD_WARNING; +				continue; +			} + +			(argv[i]->arg)[0] = '0'; +			is_wildcard = true; +		} + +		ecom = ecommunity_str2com(argv[i]->arg, ECOMMUNITY_ROUTE_TARGET, +					  0); + +		/* Put it back as was */ +		if (is_wildcard) +			(argv[i]->arg)[0] = '*'; + +		if (!ecom) { +			vty_out(vty, "%% Malformed Route Target list\n"); +			ret = CMD_WARNING; +			continue; +		} + +		ecommunity_str(ecom); + +		if (is_add) { +			if (add_rt(bgp, ecom, is_import, is_wildcard) != 0) { +				vty_out(vty, +					"%% RT specified already configured for this VRF: %s\n", +					argv[i]->arg); +				ecommunity_free(&ecom); +				ret = CMD_WARNING; +			} + +		} else { +			if (del_rt(bgp, ecom, is_import) != 0) { +				vty_out(vty, +					"%% RT specified does not match configuration for this VRF: %s\n", +					argv[i]->arg); +				ret = CMD_WARNING; +			} + +			ecommunity_free(&ecom); +		} +	} + +	return ret; +} +  /* import/export rt for l3vni-vrf */  DEFUN (bgp_evpn_vrf_rt,         bgp_evpn_vrf_rt_cmd, -       "route-target <both|import|export> RT", +       "route-target <both|import|export> RTLIST...",         "Route Target\n"         "import and export\n"         "import\n"         "export\n" -       "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN|*:OPQR|*:MN)\n")  { +	int ret = CMD_SUCCESS; +	int tmp_ret = CMD_SUCCESS;  	int rt_type;  	struct bgp *bgp = VTY_GET_CONTEXT(bgp); -	struct ecommunity *ecomadd = NULL;  	if (!bgp) -		return CMD_WARNING; +		return CMD_WARNING_CONFIG_FAILED;  	if (!strcmp(argv[1]->arg, "import"))  		rt_type = RT_TYPE_IMPORT; @@ -5810,49 +5942,82 @@ DEFUN (bgp_evpn_vrf_rt,  		rt_type = RT_TYPE_BOTH;  	else {  		vty_out(vty, "%% Invalid Route Target type\n"); -		return CMD_WARNING; +		return CMD_WARNING_CONFIG_FAILED;  	} -	ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0); -	if (!ecomadd) { -		vty_out(vty, "%% Malformed Route Target list\n"); -		return CMD_WARNING; +	if (strmatch(argv[2]->arg, "auto")) { +		vty_out(vty, "%% `auto` cannot be configured via list\n"); +		return CMD_WARNING_CONFIG_FAILED;  	} -	ecommunity_str(ecomadd);  	/* Add/update the import route-target */ -	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) { -		/* Do nothing if we already have this import route-target */ -		if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, ecomadd)) -			bgp_evpn_configure_import_rt_for_vrf(bgp, ecomadd); -	} +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) +		tmp_ret = parse_rtlist(bgp, vty, argc, argv, 2, true, true); -	/* Add/update the export route-target */ -	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) { -		/* Do nothing if we already have this export route-target */ -		if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, ecomadd)) -			bgp_evpn_configure_export_rt_for_vrf(bgp, ecomadd); +	if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS) +		ret = tmp_ret; + +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) +		tmp_ret = parse_rtlist(bgp, vty, argc, argv, 2, true, false); + +	if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS) +		ret = tmp_ret; + +	return ret; +} + +DEFPY (bgp_evpn_vrf_rt_auto, +       bgp_evpn_vrf_rt_auto_cmd, +       "route-target <both|import|export>$type auto", +       "Route Target\n" +       "import and export\n" +       "import\n" +       "export\n" +       "Automatically derive route target\n") +{ +	struct bgp *bgp = VTY_GET_CONTEXT(bgp); +	int rt_type; + +	if (!bgp) +		return CMD_WARNING_CONFIG_FAILED; + +	if (strmatch(type, "import")) +		rt_type = RT_TYPE_IMPORT; +	else if (strmatch(type, "export")) +		rt_type = RT_TYPE_EXPORT; +	else if (strmatch(type, "both")) +		rt_type = RT_TYPE_BOTH; +	else { +		vty_out(vty, "%% Invalid Route Target type\n"); +		return CMD_WARNING_CONFIG_FAILED;  	} +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) +		bgp_evpn_configure_import_auto_rt_for_vrf(bgp); + +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) +		bgp_evpn_configure_export_auto_rt_for_vrf(bgp); +  	return CMD_SUCCESS;  }  DEFUN (no_bgp_evpn_vrf_rt,         no_bgp_evpn_vrf_rt_cmd, -       "no route-target <both|import|export> RT", +       "no route-target <both|import|export> RTLIST...",         NO_STR         "Route Target\n"         "import and export\n"         "import\n"         "export\n" -       EVPN_ASN_IP_HELP_STR) +       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")  {  	struct bgp *bgp = VTY_GET_CONTEXT(bgp); -	int rt_type, found_ecomdel; -	struct ecommunity *ecomdel = NULL; +	int ret = CMD_SUCCESS; +	int tmp_ret = CMD_SUCCESS; +	int rt_type;  	if (!bgp) -		return CMD_WARNING; +		return CMD_WARNING_CONFIG_FAILED;  	if (!strcmp(argv[2]->arg, "import"))  		rt_type = RT_TYPE_IMPORT; @@ -5862,79 +6027,104 @@ DEFUN (no_bgp_evpn_vrf_rt,  		rt_type = RT_TYPE_BOTH;  	else {  		vty_out(vty, "%% Invalid Route Target type\n"); -		return CMD_WARNING; +		return CMD_WARNING_CONFIG_FAILED; +	} + +	if (!strcmp(argv[3]->arg, "auto")) { +		vty_out(vty, "%% `auto` cannot be unconfigured via list\n"); +		return CMD_WARNING_CONFIG_FAILED;  	}  	if (rt_type == RT_TYPE_IMPORT) {  		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {  			vty_out(vty,  				"%% Import RT is not configured for this VRF\n"); -			return CMD_WARNING; +			return CMD_WARNING_CONFIG_FAILED;  		}  	} else if (rt_type == RT_TYPE_EXPORT) {  		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {  			vty_out(vty,  				"%% Export RT is not configured for this VRF\n"); -			return CMD_WARNING; +			return CMD_WARNING_CONFIG_FAILED;  		}  	} else if (rt_type == RT_TYPE_BOTH) {  		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)  		    && !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {  			vty_out(vty,  				"%% Import/Export RT is not configured for this VRF\n"); -			return CMD_WARNING; +			return CMD_WARNING_CONFIG_FAILED;  		}  	} -	ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0); -	if (!ecomdel) { -		vty_out(vty, "%% Malformed Route Target list\n"); -		return CMD_WARNING; +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) +		tmp_ret = parse_rtlist(bgp, vty, argc, argv, 3, false, true); + +	if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS) +		ret = tmp_ret; + +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) +		tmp_ret = parse_rtlist(bgp, vty, argc, argv, 3, false, false); + +	if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS) +		ret = tmp_ret; + +	return ret; +} + +DEFPY (no_bgp_evpn_vrf_rt_auto, +       no_bgp_evpn_vrf_rt_auto_cmd, +       "no route-target <both|import|export>$type auto", +       NO_STR +       "Route Target\n" +       "import and export\n" +       "import\n" +       "export\n" +       "Automatically derive route target\n") +{ +	struct bgp *bgp = VTY_GET_CONTEXT(bgp); +	int rt_type; + +	if (!bgp) +		return CMD_WARNING_CONFIG_FAILED; + +	if (strmatch(type, "import")) +		rt_type = RT_TYPE_IMPORT; +	else if (strmatch(type, "export")) +		rt_type = RT_TYPE_EXPORT; +	else if (strmatch(type, "both")) +		rt_type = RT_TYPE_BOTH; +	else { +		vty_out(vty, "%% Invalid Route Target type\n"); +		return CMD_WARNING_CONFIG_FAILED;  	} -	ecommunity_str(ecomdel);  	if (rt_type == RT_TYPE_IMPORT) { -		if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, -						  ecomdel)) { -			ecommunity_free(&ecomdel); +		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD)) {  			vty_out(vty, -				"%% RT specified does not match configuration for this VRF\n"); -			return CMD_WARNING; +				"%% Import AUTO RT is not configured for this VRF\n"); +			return CMD_WARNING_CONFIG_FAILED;  		} -		bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);  	} else if (rt_type == RT_TYPE_EXPORT) { -		if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, -						  ecomdel)) { -			ecommunity_free(&ecomdel); +		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) {  			vty_out(vty, -				"%% RT specified does not match configuration for this VRF\n"); -			return CMD_WARNING; +				"%% Export AUTO RT is not configured for this VRF\n"); +			return CMD_WARNING_CONFIG_FAILED;  		} -		bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);  	} else if (rt_type == RT_TYPE_BOTH) { -		found_ecomdel = 0; - -		if (bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, -						 ecomdel)) { -			bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel); -			found_ecomdel = 1; -		} - -		if (bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, -						 ecomdel)) { -			bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel); -			found_ecomdel = 1; -		} - -		if (!found_ecomdel) { -			ecommunity_free(&ecomdel); +		if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD) && +		    !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) {  			vty_out(vty, -				"%% RT specified does not match configuration for this VRF\n"); -			return CMD_WARNING; +				"%% Import/Export AUTO RT is not configured for this VRF\n"); +			return CMD_WARNING_CONFIG_FAILED;  		}  	} -	ecommunity_free(&ecomdel); +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) +		bgp_evpn_unconfigure_import_auto_rt_for_vrf(bgp); + +	if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) +		bgp_evpn_unconfigure_export_auto_rt_for_vrf(bgp); +  	return CMD_SUCCESS;  } @@ -6421,31 +6611,62 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,  	if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {  		char *ecom_str;  		struct listnode *node, *nnode; -		struct ecommunity *ecom; +		struct vrf_route_target *l3rt;  		for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, -				       ecom)) { +				       l3rt)) { + +			if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO)) +				continue; +  			ecom_str = ecommunity_ecom2str( -				ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); -			vty_out(vty, "  route-target import %s\n", ecom_str); +				l3rt->ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + +			if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_WILD)) { +				char *vni_str = NULL; + +				vni_str = strchr(ecom_str, ':') + 1; + +				if (!vni_str) +					continue; /* This should never happen */ + +				vty_out(vty, "  route-target import *:%s\n", +					vni_str); + +			} else +				vty_out(vty, "  route-target import %s\n", +					ecom_str); +  			XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);  		}  	} +	/* import route-target auto */ +	if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD)) +		vty_out(vty, "  route-target import auto\n"); +  	/* export route-target */  	if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {  		char *ecom_str;  		struct listnode *node, *nnode; -		struct ecommunity *ecom; +		struct vrf_route_target *l3rt;  		for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, -				       ecom)) { +				       l3rt)) { + +			if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO)) +				continue; +  			ecom_str = ecommunity_ecom2str( -				ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); +				l3rt->ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);  			vty_out(vty, "  route-target export %s\n", ecom_str);  			XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);  		}  	} + +	/* export route-target auto */ +	if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) +		vty_out(vty, "  route-target export auto\n");  }  void bgp_ethernetvpn_init(void) @@ -6547,6 +6768,8 @@ void bgp_ethernetvpn_init(void)  	install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);  	install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);  	install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd); +	install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_auto_cmd); +	install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_auto_cmd);  	install_element(BGP_EVPN_NODE, &bgp_evpn_ead_es_rt_cmd);  	install_element(BGP_EVPN_NODE, &no_bgp_evpn_ead_es_rt_cmd);  	install_element(BGP_EVPN_NODE, &bgp_evpn_ead_es_frag_evi_limit_cmd);  | 
