* VNIs but the same across routers (in the same AS) for a particular
* VNI.
*/
-static void form_auto_rt(struct bgp *bgp, struct bgpevpn *vpn, struct list *rtl)
+static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
{
struct ecommunity_val eval;
struct ecommunity *ecomadd;
- encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval);
+ encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
ecomadd = ecommunity_new();
ecommunity_add_val(ecomadd, &eval);
bgp_evpn_free(bgp, vpn);
}
+/*
+ * Derive AUTO import RT for BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
+{
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+ form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+}
+
+/*
+ * Delete AUTO import RT from BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_import_delete_for_vrf(struct bgp *bgp_vrf)
+{
+ evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+}
+
+/*
+ * Derive AUTO export RT for BGP VRF - L3VNI
+ */
+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);
+}
+
+/*
+ * Delete AUTO export RT from BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_export_delete_for_vrf(struct bgp *bgp_vrf)
+{
+ evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+}
/*
* Public functions.
*/
+void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
+ struct list *rtl)
+{
+ struct listnode *node, *nnode, *node_to_del;
+ struct ecommunity *ecom, *ecom_auto;
+ struct ecommunity_val eval;
+
+ encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
+
+ ecom_auto = ecommunity_new();
+ ecommunity_add_val(ecom_auto, &eval);
+ node_to_del = NULL;
+
+ for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
+ if (ecommunity_match(ecom, ecom_auto)) {
+ ecommunity_free(&ecom);
+ node_to_del = node;
+ }
+ }
+
+ if (node_to_del)
+ list_delete_node(rtl, node_to_del);
+
+ ecommunity_free(&ecom_auto);
+}
+
+void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomadd)
+{
+ /* Remove auto generated RT */
+ 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, ecomadd);
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+
+ //TODO_MITESH: handle RT change (uninstall old routes and install new
+ //routes matching this RT)
+}
+
+void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomdel)
+{
+ struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+ struct ecommunity *ecom = NULL;
+
+ /* remove the RT from the RT list */
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+ if (ecommunity_match(ecom, ecomdel)) {
+ ecommunity_free(&ecom);
+ node_to_del = node;
+ break;
+ }
+ }
+
+ if (node_to_del)
+ list_delete_node(bgp_vrf->vrf_import_rtl, node_to_del);
+
+ /* fallback to auto import rt, if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_import_rtl)) {
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+ }
+
+ //TODO_MITESH: handle import RT change
+ //uninstall old routes, install new routes matching this RT
+}
+
+void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomadd)
+{
+ /* remove auto-generated RT */
+ 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, ecomadd);
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
+
+ /* TODO_MITESH: update all routes */
+}
+
+void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomdel)
+{
+ struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+ struct ecommunity *ecom = NULL;
+
+ /* Remove the RT from the RT list */
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
+ if (ecommunity_match(ecom, ecomdel)) {
+ ecommunity_free(&ecom);
+ node_to_del = node;
+ break;
+ }
+ }
+
+ if (node_to_del)
+ list_delete_node(bgp_vrf->vrf_export_rtl, node_to_del);
+
+ /* fall back to auto-generated RT if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_export_rtl)) {
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+ }
+
+ //TODO_MITESH: update all mac-ip routes
+}
+
/*
* Handle change to BGP router id. This is invoked twice by the change
* handler, first before the router id has been changed and then after
*/
void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
{
- form_auto_rt(bgp, vpn, vpn->import_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->import_rtl);
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, vpn->export_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->export_rtl);
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
}
/* set the router mac - to be used in mac-ip routes for this vrf */
memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr));
- //TODO_MITESH: auto derive RD/RT
+ /* auto derive RD/RT */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
//TODO_MITESH: update all the local mac-ip routes with l3vni/rmac info
/* remove the Rmac from the BGP vrf */
memset(&bgp_vrf->rmac, 0, sizeof(struct ethaddr));
- /* TODO_MITESH: delete auto RD/RT */
+ /* delete RD/RT */
+ if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl))
+ list_delete(bgp_vrf->vrf_import_rtl);
+ if (bgp_vrf->vrf_export_rtl && !list_isempty(bgp_vrf->vrf_export_rtl))
+ list_delete(bgp_vrf->vrf_export_rtl);
/* TODO_MITESH: update all local mac-ip routes */
if (bgp->vnihash)
hash_free(bgp->vnihash);
bgp->vnihash = NULL;
+ if (bgp->vrf_import_rtl)
+ list_delete(bgp->vrf_import_rtl);
+ bgp->vrf_import_rtl = NULL;
+ if (bgp->vrf_export_rtl)
+ list_delete(bgp->vrf_export_rtl);
+ bgp->vrf_export_rtl = NULL;
bf_free(bgp->rd_idspace);
}
bgp->import_rt_hash =
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
"BGP Import RT Hash");
+ bgp->vrf_import_rtl = list_new();
+ bgp->vrf_import_rtl->cmp =
+ (int (*)(void *, void *))evpn_route_target_cmp;
+
+ bgp->vrf_export_rtl = list_new();
+ bgp->vrf_export_rtl->cmp =
+ (int (*)(void *, void *))evpn_route_target_cmp;
bf_init(bgp->rd_idspace, UINT16_MAX);
/*assign 0th index in the bitfield, so that we start with id 1*/
bf_assign_zero_index(bgp->rd_idspace);
p->prefix.ip.ipaddr_v4 = originator_ip;
}
-
+extern void evpn_rt_delete_auto(struct bgp*, vni_t, struct list*);
+extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp*,
+ struct ecommunity*);
+extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp*,
+ struct ecommunity*);
+extern void bgp_evpn_configure_import_rt_for_vrf(struct bgp*,
+ struct ecommunity*);
+extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp*,
+ struct ecommunity*);
extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
struct bgpevpn *vpn);
extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
}
#if defined(HAVE_CUMULUS)
-static void evpn_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn,
- struct list *rtl)
-{
- struct listnode *node, *nnode, *node_to_del;
- struct ecommunity *ecom, *ecom_auto;
- struct ecommunity_val eval;
-
- encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval);
-
- ecom_auto = ecommunity_new();
- ecommunity_add_val(ecom_auto, &eval);
- node_to_del = NULL;
-
- for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
- if (ecommunity_match(ecom, ecom_auto)) {
- ecommunity_free(&ecom);
- node_to_del = node;
- }
- }
-
- if (node_to_del)
- list_delete_node(rtl, node_to_del);
-
- ecommunity_free(&ecom_auto);
-}
static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
{
- evpn_rt_delete_auto(bgp, vpn, vpn->import_rtl);
+ evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
}
static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
{
- evpn_rt_delete_auto(bgp, vpn, vpn->export_rtl);
+ evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl);
}
/*
return 0;
}
+/* display L3VNI related info for a VRF instance */
+DEFUN (show_bgp_vrf_l3vni_info,
+ show_bgp_vrf_l3vni_info_cmd,
+ "show bgp vrf VRFNAME l3vni info",
+ SHOW_STR
+ BGP_STR
+ "show bgp vrf\n"
+ "VRF Name\n"
+ "L3-VNI\n"
+ "L3-VNI info\n")
+{
+ char buf[ETHER_ADDR_STRLEN];
+ int idx_vrf = 3;
+ const char *name = NULL;
+ struct bgp *bgp = NULL;
+ struct listnode *node = NULL;
+ //struct bgpevpn *vpn = NULL;
+ struct ecommunity *ecom = NULL;
+
+ name = argv[idx_vrf]->arg;
+ bgp = bgp_lookup_by_name(name);
+ if (!bgp) {
+ vty_out(vty, "BGP instance for VRF %s not found",
+ name);
+ return CMD_WARNING;
+ }
+
+ vty_out(vty, "BGP VRF: %s\n", name);
+ vty_out(vty, " L3-VNI: %u\n", bgp->l3vni);
+ vty_out(vty, " Rmac: %s\n",
+ prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
+ /*vty_out(vty, " L2-VNI List:\n");
+ vty_out(vty, " ");
+ for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
+ vty_out(vty, "%u ", vpn->vni);
+ 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));
+ 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));
+ vty_out(vty, "\n");
+
+ return CMD_SUCCESS;
+}
+
+/* import/export rt for l3vni-vrf */
+DEFUN (bgp_evpn_vrf_rt,
+ bgp_evpn_vrf_rt_cmd,
+ "route-target <both|import|export> RT",
+ "Route Target\n"
+ "import and export\n"
+ "import\n"
+ "export\n"
+ "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ int rt_type;
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ struct ecommunity *ecomadd = NULL;
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ 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;
+ }
+
+ /* Add/update the import route-target */
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
+ ecomadd = ecommunity_str2com(argv[2]->arg,
+ ECOMMUNITY_ROUTE_TARGET, 0);
+ if (!ecomadd) {
+ vty_out(vty, "%% Malformed Route Target list\n");
+ return CMD_WARNING;
+ }
+ ecommunity_str(ecomadd);
+
+ /* 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);
+ }
+
+ /* Add/update the export route-target */
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
+ ecomadd = ecommunity_str2com(argv[2]->arg,
+ ECOMMUNITY_ROUTE_TARGET, 0);
+ if (!ecomadd) {
+ vty_out(vty, "%% Malformed Route Target list\n");
+ return CMD_WARNING;
+ }
+ ecommunity_str(ecomadd);
+
+ /* 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);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rt,
+ no_bgp_evpn_vrf_rt_cmd,
+ "no route-target <both|import|export> RT",
+ NO_STR
+ "Route Target\n"
+ "import and export\n"
+ "import\n"
+ "export\n"
+ "ASN:XX or A.B.C.D:XX\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ int rt_type, found_ecomdel;
+ struct ecommunity *ecomdel = NULL;
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ 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;
+ }
+
+ 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;
+ }
+ } 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;
+ }
+ } 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;
+ }
+ }
+
+ ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
+ if (!ecomdel) {
+ vty_out(vty, "%% Malformed Route Target list\n");
+ return CMD_WARNING;
+ }
+ ecommunity_str(ecomdel);
+
+ if (rt_type == RT_TYPE_IMPORT) {
+ if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
+ ecomdel)) {
+ vty_out(vty,
+ "%% RT specified does not match configuration for this VRF\n");
+ return CMD_WARNING;
+ }
+ 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)) {
+ vty_out(vty,
+ "%% RT specified does not match configuration for this VRF\n");
+ return CMD_WARNING;
+ }
+ 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) {
+ vty_out(vty,
+ "%% RT specified does not match configuration for this VRF\n");
+ return CMD_WARNING;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
DEFUN (bgp_evpn_vni_rt,
bgp_evpn_vni_rt_cmd,
install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd);
+ install_element(VIEW_NODE, &show_bgp_vrf_l3vni_info_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd);
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
+ install_element(BGP_NODE, &bgp_evpn_vrf_rt_cmd);
+ install_element(BGP_NODE, &no_bgp_evpn_vrf_rt_cmd);
install_element(BGP_EVPN_VNI_NODE,
&bgp_evpn_advertise_default_gw_vni_cmd);
install_element(BGP_EVPN_VNI_NODE,
/* vrf flags */
uint32_t vrf_flags;
#define BGP_VRF_AUTO (1 << 0)
+#define BGP_VRF_IMPORT_RT_CFGD (1 << 1)
+#define BGP_VRF_EXPORT_RT_CFGD (1 << 2)
+
+ /* import rt list for the vrf instance */
+ struct list *vrf_import_rtl;
+
+ /* export rt list for the vrf instance */
+ struct list *vrf_export_rtl;
QOBJ_FIELDS
};