From: mitesh Date: Wed, 25 Oct 2017 23:49:18 +0000 (-0700) Subject: bgpd: RD derivation for VRF X-Git-Tag: frr-4.0-dev~58^2~26 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=676f83b991924c29f1d9cee44f321f36123f4361;p=matthieu%2Ffrr.git bgpd: RD derivation for VRF 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 --- diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a17e3bea79..0558c04dde 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -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) diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 1b7e4d719e..26a0260794 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -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, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 33d166112a..c22e6770e4 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -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, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d456d66933..8087d3514a 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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;