return 0;
}
+/*
+ * update and advertise local routes for a VRF as type-5 routes.
+ * This is invoked upon RD change for a VRF. Note taht the processing is only
+ * done in the global route table using the routes which already exist in the
+ * VRF routing table
+ */
+static int update_advertise_vrf_routes(struct bgp *bgp_vrf)
+{
+ return 0;
+}
+
+/*
+ * Delete and withdraw all type-5 routes for the RD corresponding to VRF.
+ * This is invoked upon VRF RD change. The processing is done only from global
+ * table.
+ */
+static int delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
+{
+ return 0;
+}
+
/*
* Update and advertise local routes for a VNI. Invoked upon router-id
* change. Note that the processing is done only on the global route table
* 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
* the router id has been changed. The first invocation will result in
- * local routes for all VNIs being deleted and withdrawn and the next
+ * local routes for all VNIs/VRF being deleted and withdrawn and the next
* will result in the routes being re-advertised.
*/
void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
{
- if (withdraw)
+ if (withdraw) {
+
+ /* delete and withdraw all the type-5 routes
+ stored in the global table for this vrf */
+ delete_withdraw_vrf_routes(bgp);
+
+ /* delete all the VNI routes (type-2/type-3) routes for all the
+ * L2-VNIs */
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *,
void *))withdraw_router_id_vni,
bgp);
- else
+ } else {
+
+ /* advertise all routes in the vrf as type-5 routes with the new
+ * RD */
+ update_advertise_vrf_routes(bgp);
+
+ /* advertise all the VNI routes (type-2/type-3) routes with the
+ * new RD*/
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *,
void *))update_router_id_vni,
bgp);
+ }
}
/*
return update_routes_for_vni(bgp, vpn);
}
+void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf,
+ int withdraw)
+{
+ if (withdraw)
+ delete_withdraw_vrf_routes(bgp_vrf);
+ else
+ update_advertise_vrf_routes(bgp_vrf);
+}
+
/*
* Handle change to RD. This is invoked twice by the change handler,
* first before the RD has been changed and then after the RD has
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
}
+/*
+ * Derive RD automatically for VNI using passed information - it
+ * is of the form RouterId:unique-id-for-vni.
+ */
+void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
+{
+ char buf[100];
+
+ bgp->vrf_prd.family = AF_UNSPEC;
+ bgp->vrf_prd.prefixlen = 64;
+ sprintf(buf, "%s:%hu", inet_ntoa(bgp->router_id), bgp->vrf_rd_id);
+ str2prefix_rd(buf, &bgp->vrf_prd);
+}
+
/*
* Derive RD automatically for VNI using passed information - it
* is of the form RouterId:unique-id-for-vni.
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);
+ bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
/* link all corresponding l2vnis */
hash_iterate(bgp_def->vnihash,
if (bgp->l2vnis)
list_delete_and_null(&bgp->l2vnis);
bgp->l2vnis = NULL;
+ bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
}
/*
* Create
* VNI hash table
* hash for RT to VNI
- * unique rd id space for auto derivation of RD for VNIs
+ * assign a unique rd id for auto derivation of vrf_prd
*/
void bgp_evpn_init(struct bgp *bgp)
{
bgp->l2vnis = list_new();
bgp->l2vnis->cmp =
(int (*)(void *, void *))vni_hash_cmp;
+ bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id);
+
}
void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
#define RT_TYPE_EXPORT 2
#define RT_TYPE_BOTH 3
+static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
+{
+ return (CHECK_FLAG(bgp_vrf->vrf_flags,
+ BGP_VRF_RD_CFGD));
+}
+
+static inline int bgp_evpn_vrf_rd_matches_existing(struct bgp *bgp_vrf,
+ struct prefix_rd *prd)
+{
+ return (memcmp(&bgp_vrf->vrf_prd.val, prd->val, ECOMMUNITY_SIZE) == 0);
+}
+
+static inline int is_evpn_prefix_routes_adv_enabled(struct bgp *bgp_vrf)
+{
+ if (!bgp_vrf->l3vni ||
+ !CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_EVPN_PREFIX_ROUTE))
+ return 0;
+
+ return 1;
+}
+
static inline vni_t bgpevpn_get_l3vni(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
struct ecommunity*);
extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
struct bgpevpn *vpn);
+extern void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw);
extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
int withdraw);
extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_derive_auto_rt_export(struct bgp *bgp,
struct bgpevpn *vpn);
extern void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn);
+extern void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp);
extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
bgp_evpn_handle_export_rt_change(bgp, vpn);
}
+/*
+ * Configure RD for VRF
+ */
+static void evpn_configure_vrf_rd(struct bgp *bgp_vrf,
+ struct prefix_rd *rd)
+{
+ /* If we have already advertise type-5 routes with a diffrent RD, we
+ * have to delete and withdraw them first*/
+ if (is_evpn_prefix_routes_adv_enabled(bgp_vrf))
+ bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
+
+ /* update RD */
+ memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
+
+ /* We have a new RD for VRF.
+ * Advertise all type-5 routes again with the new RD */
+ if (is_evpn_prefix_routes_adv_enabled(bgp_vrf))
+ bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
+
+}
+
+/*
+ * Unconfigure RD for VRF
+ */
+static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
+{
+ /* If we have already advertise type-5 routes with a diffrent RD, we
+ * have to delete and withdraw them first*/
+ if (is_evpn_prefix_routes_adv_enabled(bgp_vrf))
+ bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
+
+ /* fall back to default RD */
+ bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+
+ /* We have a new RD for VRF.
+ * Advertise all type-5 routes again with the new RD */
+ if (is_evpn_prefix_routes_adv_enabled(bgp_vrf))
+ bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
+}
+
/*
* Configure RD for a VNI (vty handler)
*/
return CMD_SUCCESS;
}
+DEFUN (bgp_evpn_vrf_rd,
+ bgp_evpn_vrf_rd_cmd,
+ "rd ASN:NN_OR_IP-ADDRESS:NN",
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n")
+{
+ int ret;
+ struct prefix_rd prd;
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp_vrf)
+ return CMD_WARNING;
+
+ ret = str2prefix_rd(argv[1]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher\n");
+ return CMD_WARNING;
+ }
+
+ /* If same as existing value, there is nothing more to do. */
+ if (bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd))
+ return CMD_SUCCESS;
+
+ /* Configure or update the RD. */
+ evpn_configure_vrf_rd(bgp_vrf, &prd);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rd,
+ no_bgp_evpn_vrf_rd_cmd,
+ "no rd ASN:NN_OR_IP-ADDRESS:NN",
+ NO_STR
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n")
+{
+ int ret;
+ struct prefix_rd prd;
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp_vrf)
+ return CMD_WARNING;
+
+ ret = str2prefix_rd(argv[2]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher\n");
+ return CMD_WARNING;
+ }
+
+ /* Check if we should disallow. */
+ if (!is_vrf_rd_configured(bgp_vrf)) {
+ vty_out(vty, "%% RD is not configured for this VRF\n");
+ return CMD_WARNING;
+ }
+
+ if (!bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd)) {
+ vty_out(vty,
+ "%% RD specified does not match configuration for this VRF\n");
+ return CMD_WARNING;
+ }
+
+ evpn_unconfigure_vrf_rd(bgp_vrf);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rd_without_val,
+ no_bgp_evpn_vrf_rd_without_val_cmd,
+ "no rd",
+ NO_STR
+ "Route Distinguisher\n")
+{
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp_vrf)
+ return CMD_WARNING;
+
+ /* Check if we should disallow. */
+ if (!is_vrf_rd_configured(bgp_vrf)) {
+ vty_out(vty, "%% RD is not configured for this VRF\n");
+ return CMD_WARNING;
+ }
+
+ evpn_unconfigure_vrf_rd(bgp_vrf);
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_evpn_vni_rd,
bgp_evpn_vni_rd_cmd,
"rd ASN:NN_OR_IP-ADDRESS:NN",
JSON_STR)
{
char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
int idx_vrf = 3;
const char *name = NULL;
struct bgp *bgp = NULL;
for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
vty_out(vty, "%s ", ecommunity_str(ecom));
vty_out(vty, "\n");
+ vty_out(vty, " RD: %s\n",
+ prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
} else {
json_object_string_add(json, "vrf", name);
json_object_int_add(json, "l3vni", bgp->l3vni);
json_object_new_string(
ecommunity_str(ecom)));
json_object_object_add(json, "import-rts", json_import_rts);
+ json_object_string_add(
+ json, "rd",
+ prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
}
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_rd_cmd);
+ install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_cmd);
+ 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_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)
+#define BGP_VRF_AUTO (1 << 0)
+#define BGP_VRF_ADVERTISE_EVPN_PREFIX_ROUTE (1 << 1)
+#define BGP_VRF_IMPORT_RT_CFGD (1 << 2)
+#define BGP_VRF_EXPORT_RT_CFGD (1 << 3)
+#define BGP_VRF_RD_CFGD (1 << 4)
+
+ /* unique ID for auto derivation of RD for this vrf */
+ uint16_t vrf_rd_id;
+
+ /* RD for this VRF */
+ struct prefix_rd vrf_prd;
/* import rt list for the vrf instance */
struct list *vrf_import_rtl;