* just retain the local-admin field.
*/
static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
- struct ecommunity_val *src)
+ const struct ecommunity_val *src)
{
uint8_t type;
}
/*
- * Map one RT to specified VRF.
- * bgp_vrf = BGP vrf instance
+ * Converts the RT to Ecommunity Value and adjusts masking based
+ * on flags set for RT.
*/
-static void map_vrf_to_rt(struct bgp *bgp_vrf, struct ecommunity_val *eval)
+static void vrf_rt2ecom_val(struct ecommunity_val *to_eval,
+ const struct vrf_route_target *l3rt, int iter)
{
- struct vrf_irt_node *irt = NULL;
- struct ecommunity_val eval_tmp;
+ const struct ecommunity_val *eval;
- /* If using "automatic" RT,
+ eval = (const struct ecommunity_val *)(l3rt->ecom->val +
+ (iter * ECOMMUNITY_SIZE));
+ /* If using "automatic" or "wildcard *" RT,
* we only care about the local-admin sub-field.
* This is to facilitate using L3VNI(VRF-VNI)
- * as the RT for EBGP peering too.
+ * as the RT for EBGP peering too and simplify
+ * configurations by allowing any ASN via '*'.
*/
- memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
- mask_ecom_global_admin(&eval_tmp, eval);
+ memcpy(to_eval, eval, ECOMMUNITY_SIZE);
- irt = lookup_vrf_import_rt(&eval_tmp);
- if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
- /* Already mapped. */
- return;
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO) ||
+ CHECK_FLAG(l3rt->flags, BGP_VRF_RT_WILD))
+ mask_ecom_global_admin(to_eval, eval);
+}
- if (!irt)
- irt = vrf_import_rt_new(&eval_tmp);
+/*
+ * Map one RT to specified VRF.
+ * bgp_vrf = BGP vrf instance
+ */
+static void map_vrf_to_rt(struct bgp *bgp_vrf, struct vrf_route_target *l3rt)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < l3rt->ecom->size; i++) {
+ struct vrf_irt_node *irt = NULL;
+ struct ecommunity_val eval_tmp;
+
+ /* Adjust masking for value */
+ vrf_rt2ecom_val(&eval_tmp, l3rt, i);
- /* Add VRF to the list for this RT. */
- listnode_add(irt->vrfs, bgp_vrf);
+ irt = lookup_vrf_import_rt(&eval_tmp);
+
+ if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+ return; /* Already mapped. */
+
+ if (!irt)
+ irt = vrf_import_rt_new(&eval_tmp);
+
+ /* Add VRF to the list for this RT. */
+ listnode_add(irt->vrfs, bgp_vrf);
+ }
}
/*
* VRFs for this RT, then the RT hash is deleted.
* bgp_vrf: BGP VRF specific instance
*/
-static void unmap_vrf_from_rt(struct bgp *bgp_vrf, struct vrf_irt_node *irt)
+static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
+ struct vrf_route_target *l3rt)
{
- /* Delete VRF from list for this RT. */
- listnode_delete(irt->vrfs, bgp_vrf);
- if (!listnode_head(irt->vrfs)) {
- vrf_import_rt_free(irt);
+ uint32_t i;
+
+ for (i = 0; i < l3rt->ecom->size; i++) {
+ struct vrf_irt_node *irt;
+ struct ecommunity_val eval_tmp;
+
+ /* Adjust masking for value */
+ vrf_rt2ecom_val(&eval_tmp, l3rt, i);
+
+ irt = lookup_vrf_import_rt(&eval_tmp);
+
+ if (!irt)
+ return; /* Not mapped */
+
+ /* Delete VRF from list for this RT. */
+ listnode_delete(irt->vrfs, bgp_vrf);
+
+ if (!listnode_head(irt->vrfs))
+ vrf_import_rt_free(irt);
}
}
* VNIs but the same across routers (in the same AS) for a particular
* VNI.
*/
-static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
+static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
+ bool is_l3)
{
struct ecommunity_val eval;
struct ecommunity *ecomadd;
+ struct ecommunity *ecom;
struct vrf_route_target *l3rt;
struct vrf_route_target *newrt;
bool ecom_found = false;
ecomadd = ecommunity_new();
ecommunity_add_val(ecomadd, &eval, false, false);
- for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt))
- if (ecommunity_cmp(ecomadd, l3rt->ecom)) {
- ecom_found = true;
- break;
- }
+
+ if (is_l3) {
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt))
+ if (ecommunity_cmp(ecomadd, l3rt->ecom)) {
+ ecom_found = true;
+ break;
+ }
+ } else {
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
+ if (ecommunity_cmp(ecomadd, ecom)) {
+ ecom_found = true;
+ break;
+ }
+ }
if (!ecom_found) {
- newrt = evpn_vrf_rt_new(ecomadd);
- listnode_add_sort(rtl, newrt);
+ if (is_l3) {
+ newrt = evpn_vrf_rt_new(ecomadd);
+ /* Label it as autoderived */
+ SET_FLAG(newrt->flags, BGP_VRF_RT_AUTO);
+ listnode_add_sort(rtl, newrt);
+ } else
+ listnode_add_sort(rtl, ecomadd);
} else
ecommunity_free(&ecomadd);
}
{
struct bgp *bgp_evpn = NULL;
- form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+ form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl, true);
/* Map RT to VRF */
bgp_evpn = bgp_get_evpn();
+
if (!bgp_evpn)
return;
+
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
}
*/
static void evpn_auto_rt_export_add_for_vrf(struct bgp *bgp_vrf)
{
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
- form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+ form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl, true);
}
/*
struct vrf_route_target *l3rt = NULL;
struct ecommunity *ecom = NULL;
- /* remove the RT from the RT list */
-
if (is_l3) {
for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
if (ecommunity_match(l3rt->ecom, ecomdel)) {
}
}
+
if (node_to_del)
list_delete_node(rt_list, node_to_del);
}
if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN;
+
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
ecom_auto = ecommunity_new();
ecommunity_add_val(ecom_auto, &eval, false, false);
- /* Remove rt */
rt_list_remove_node(rtl, ecom_auto, is_l3);
ecommunity_free(&ecom_auto);
}
-void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
- struct ecommunity *ecomadd)
+static void evpn_vrf_rt_routes_map(struct bgp *bgp_vrf)
{
- struct vrf_route_target *newrt;
-
- newrt = evpn_vrf_rt_new(ecomadd);
+ /* map VRFs to its RTs and install routes matching this new RT */
+ if (is_l3vni_live(bgp_vrf)) {
+ bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+ install_routes_for_vrf(bgp_vrf);
+ }
+}
+static void evpn_vrf_rt_routes_unmap(struct bgp *bgp_vrf)
+{
/* uninstall routes from vrf */
if (is_l3vni_live(bgp_vrf))
uninstall_routes_for_vrf(bgp_vrf);
/* Cleanup the RT to VRF mapping */
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+}
- /* Remove auto generated RT */
- evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
+static bool rt_list_has_cfgd_rt(struct list *rt_list)
+{
+ struct listnode *node = NULL, *nnode = NULL;
+ struct vrf_route_target *l3rt = NULL;
+
+ for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
+ if (!CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ return true;
+ }
+
+ return false;
+}
+
+static void unconfigure_import_rt_for_vrf_fini(struct bgp *bgp_vrf)
+{
+ if (!bgp_vrf->vrf_import_rtl)
+ return; /* this should never fail */
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Nothing to do if no vni */
+
+ /* fall back to auto-generated RT if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_import_rtl))
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+}
+
+static void unconfigure_export_rt_for_vrf_fini(struct bgp *bgp_vrf)
+{
+
+ if (!bgp_vrf->vrf_export_rtl)
+ return; /* this should never fail */
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Nothing to do if no vni */
+
+ /* fall back to auto-generated RT if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_export_rtl))
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+}
+
+void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomadd,
+ bool is_wildcard)
+{
+ struct vrf_route_target *newrt;
+
+ newrt = evpn_vrf_rt_new(ecomadd);
+
+ if (is_wildcard)
+ SET_FLAG(newrt->flags, BGP_VRF_RT_WILD);
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ /* Remove auto generated RT if not configured */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
/* Add the newly configured RT to RT list */
listnode_add_sort(bgp_vrf->vrf_import_rtl, newrt);
+
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- /* map VRF to its RTs and install routes matching the new RTs */
- if (is_l3vni_live(bgp_vrf)) {
- bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- install_routes_for_vrf(bgp_vrf);
- }
+ evpn_vrf_rt_routes_map(bgp_vrf);
+}
+
+void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ return; /* Already configured */
+
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Wait for VNI before adding rts */
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel)
{
- /* uninstall routes from vrf */
- if (is_l3vni_live(bgp_vrf))
- uninstall_routes_for_vrf(bgp_vrf);
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ return; /* Already un-configured */
- /* Cleanup the RT to VRF mapping */
- bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
/* Remove rt */
rt_list_remove_node(bgp_vrf->vrf_import_rtl, ecomdel, true);
- assert(bgp_vrf->vrf_import_rtl);
- /* fallback to auto import rt, if this was the last RT */
- if (bgp_vrf->vrf_import_rtl && list_isempty(bgp_vrf->vrf_import_rtl)) {
+ if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_import_rtl))
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- if (is_l3vni_live(bgp_vrf))
- evpn_auto_rt_import_add_for_vrf(bgp_vrf);
- }
- /* map VRFs to its RTs and install routes matching this new RT */
- if (is_l3vni_live(bgp_vrf)) {
- bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- install_routes_for_vrf(bgp_vrf);
- }
+ unconfigure_import_rt_for_vrf_fini(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
+}
+
+void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ return; /* Already un-configured */
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ /* remove auto-generated RT */
+ evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
+
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
+
+ unconfigure_import_rt_for_vrf_fini(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
newrt = evpn_vrf_rt_new(ecomadd);
- /* remove auto-generated RT */
- evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
+ /* Remove auto generated RT if not configured */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
/* Add the new RT to the RT list */
listnode_add_sort(bgp_vrf->vrf_export_rtl, newrt);
+
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
if (is_l3vni_live(bgp_vrf))
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
}
+void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ return; /* Already configured */
+
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Wait for VNI before adding rts */
+
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+}
+
void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel)
{
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+ return; /* Already un-configured */
+
/* Remove rt */
rt_list_remove_node(bgp_vrf->vrf_export_rtl, ecomdel, true);
- /*
- * Temporary assert to make SA happy.
- * The ALL_LIST_ELEMENTS macro above has a NULL check
- * which means that SA is going to complain about
- * the list_isempty call, which doesn't NULL check.
- * So until we get this situation cleaned up, here
- * we are.
- */
- assert(bgp_vrf->vrf_export_rtl);
-
- /* fall back to auto-generated RT if this was the last RT */
- if (list_isempty(bgp_vrf->vrf_export_rtl)) {
+ if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_export_rtl))
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
- if (is_l3vni_live(bgp_vrf))
- evpn_auto_rt_export_add_for_vrf(bgp_vrf);
- }
- if (is_l3vni_live(bgp_vrf))
- bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+ unconfigure_export_rt_for_vrf_fini(bgp_vrf);
+}
+
+void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ return; /* Already un-configured */
+
+ /* remove auto-generated RT */
+ evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
+
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
+
+ unconfigure_export_rt_for_vrf_fini(bgp_vrf);
}
/*
*/
void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
{
- uint32_t i = 0;
- struct ecommunity_val *eval = NULL;
- struct listnode *node = NULL, *nnode = NULL;
+ struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt)) {
- for (i = 0; i < l3rt->ecom->size; i++) {
- eval = (struct ecommunity_val *)(l3rt->ecom->val
- + (i
- * ECOMMUNITY_SIZE));
- map_vrf_to_rt(bgp_vrf, eval);
- }
- }
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
+ map_vrf_to_rt(bgp_vrf, l3rt);
}
/*
*/
void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
{
- uint32_t i;
- struct ecommunity_val *eval;
struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt)) {
- for (i = 0; i < l3rt->ecom->size; i++) {
- struct vrf_irt_node *irt;
- struct ecommunity_val eval_tmp;
-
- eval = (struct ecommunity_val *)(l3rt->ecom->val
- + (i
- * ECOMMUNITY_SIZE));
- /* If using "automatic" RT, we only care about the
- * local-admin sub-field.
- * This is to facilitate using VNI as the RT for EBGP
- * peering too.
- */
- memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags,
- BGP_VRF_IMPORT_RT_CFGD))
- mask_ecom_global_admin(&eval_tmp, eval);
-
- irt = lookup_vrf_import_rt(&eval_tmp);
- if (irt)
- unmap_vrf_from_rt(bgp_vrf, irt);
- }
- }
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
+ unmap_vrf_from_rt(bgp_vrf, l3rt);
}
-
/*
* Map the RTs (configured or automatically derived) of a VNI to the VNI.
* The mapping will be used during route processing.
*/
void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
{
- form_auto_rt(bgp, vpn->vni, vpn->import_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->import_rtl, false);
UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
/* Map RT to VNI */
*/
void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
{
- form_auto_rt(bgp, vpn->vni, vpn->export_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->export_rtl, false);
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
}
}
/* Map auto derive or configured RTs */
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD) ||
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
else
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD) ||
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
/* auto derive RD */
return CMD_SUCCESS;
}
-static int add_rt(struct bgp *bgp, struct ecommunity *ecom, bool is_import)
+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);
+ bgp_evpn_configure_import_rt_for_vrf(bgp, ecom,
+ is_wildcard);
else
return -1;
} else {
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;
ecommunity_str(ecom);
if (is_add) {
- if (add_rt(bgp, ecom, is_import) != 0) {
+ 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);
"import and export\n"
"import\n"
"export\n"
- "Space separated route target list (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;
return CMD_WARNING_CONFIG_FAILED;
}
+ if (strmatch(argv[2]->arg, "auto")) {
+ vty_out(vty, "%% `auto` cannot be configured via list\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
/* Add/update the import route-target */
if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT)
tmp_ret = parse_rtlist(bgp, vty, argc, argv, 2, true, true);
"export\n"
"Automatically derive route target\n")
{
- // TODO: auto
- vty_out(vty, "AUTO TODO\n");
- return CMD_WARNING_CONFIG_FAILED;
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ int rt_type;
+
+ if (!bgp)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (!strcmp(argv[1]->arg, "import"))
+ rt_type = RT_TYPE_IMPORT;
+ else if (!strcmp(argv[1]->arg, "export"))
+ rt_type = RT_TYPE_EXPORT;
+ else if (!strcmp(argv[1]->arg, "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,
int rt_type;
if (!bgp)
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
if (!strcmp(argv[2]->arg, "import"))
rt_type = RT_TYPE_IMPORT;
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;
}
}
"export\n"
"Automatically derive route target\n")
{
- // TODO: auto
- vty_out(vty, "AUTO TODO\n");
- return CMD_WARNING_CONFIG_FAILED;
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ int rt_type;
+
+ if (!bgp)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (!strcmp(argv[2]->arg, "import"))
+ rt_type = RT_TYPE_IMPORT;
+ else if (!strcmp(argv[2]->arg, "export"))
+ rt_type = RT_TYPE_EXPORT;
+ else if (!strcmp(argv[2]->arg, "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_IMPORT) {
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD)) {
+ vty_out(vty,
+ "%% Import AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ } else if (rt_type == RT_TYPE_EXPORT) {
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) {
+ vty_out(vty,
+ "%% Export AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ } else if (rt_type == RT_TYPE_BOTH) {
+ 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,
+ "%% Import/Export AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ 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;
}
DEFPY(bgp_evpn_ead_ess_frag_evi_limit, bgp_evpn_ead_es_frag_evi_limit_cmd,
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
l3rt)) {
+
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ continue;
+
ecom_str = ecommunity_ecom2str(
l3rt->ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, " route-target import %s\n", ecom_str);
+
+ 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;
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
l3rt)) {
+
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ continue;
+
ecom_str = ecommunity_ecom2str(
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)