]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: RD derivation for VRF
authormitesh <mitesh@cumulusnetworks.com>
Wed, 25 Oct 2017 23:49:18 +0000 (16:49 -0700)
committerMitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>
Thu, 14 Dec 2017 18:57:07 +0000 (10:57 -0800)
1. VRF RD can be auto-derived (simillar to RD for a VNI)
2. VRF RD can be configured manually through a config

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgpd.h

index a17e3bea79ad634373fbaaf616ac1b47ffbaf069..0558c04dde0fa55bee0ed7486e61381be80124ca 100644 (file)
@@ -2233,6 +2233,27 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
        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
@@ -2914,21 +2935,36 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
  * 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);
+       }
 }
 
 /*
@@ -2939,6 +2975,15 @@ int bgp_evpn_handle_export_rt_change(struct bgp *bgp, struct bgpevpn *vpn)
        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
@@ -3388,6 +3433,20 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
        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.
@@ -3703,6 +3762,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni,
                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,
@@ -3937,6 +3997,7 @@ void bgp_evpn_cleanup(struct bgp *bgp)
        if (bgp->l2vnis)
                list_delete_and_null(&bgp->l2vnis);
        bgp->l2vnis = NULL;
+       bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
 }
 
 /*
@@ -3944,7 +4005,7 @@ void bgp_evpn_cleanup(struct bgp *bgp)
  * 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)
 {
@@ -3966,6 +4027,8 @@ 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)
index 1b7e4d719ec4a0efa0c34df3f072d9d926e72243..26a026079412cbc96c039e68a6216be429e6edb2 100644 (file)
@@ -114,6 +114,27 @@ struct vrf_irt_node {
 #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;
@@ -313,6 +334,7 @@ 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_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);
@@ -327,6 +349,7 @@ extern void bgp_evpn_derive_auto_rt_import(struct bgp *bgp,
 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,
index 33d166112ad294b360d90f70d520fca943373c90..c22e6770e4c5711b83dae0d6d601c0fd23826de8 100644 (file)
@@ -1489,6 +1489,47 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
                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)
  */
@@ -3201,6 +3242,91 @@ DEFUN_NOSH (exit_vni,
        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",
@@ -3320,6 +3446,7 @@ DEFUN (show_bgp_vrf_l3vni_info,
        JSON_STR)
 {
        char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
        int idx_vrf = 3;
        const char *name = NULL;
        struct bgp *bgp = NULL;
@@ -3375,6 +3502,8 @@ DEFUN (show_bgp_vrf_l3vni_info,
                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);
@@ -3400,6 +3529,9 @@ DEFUN (show_bgp_vrf_l3vni_info,
                                              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));
 
        }
 
@@ -3857,6 +3989,9 @@ void bgp_ethernetvpn_init(void)
        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,
index d456d669332a62327699cab24cc34a728beea141..8087d3514a02ef43f15c1b303e3d09fd9b4482da 100644 (file)
@@ -420,9 +420,17 @@ struct bgp {
 
        /* 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;