From 636f76088d1148711f3cdbffd2b1c807b773d664 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Thu, 7 Mar 2019 21:26:14 -0800 Subject: [PATCH] bgpd: router-id change reflect to vpn auto rd rt VRF route leak auto RD and RT uses router-id, when a router-id changes for a bgp instance, change associated vpn RD and RT values. Withdraw old RD/RT routes from vpn and with new RD/RT values advertise new routes to vpn. One of the sceanrio is restarting frr: A router-id change may not have reflected for bgp vrf instance X, while import vrf X under bgp vrf instance Y. Once router-id changes for bgp VRF X, change RD and RTs from export VRF and imported VRFs. Readvertise routes with new values to VPN. Ticket:CM-24149 Reviewed By:CCR-8394 Testing Done: Validated via configured multiple bgp VRF instances and enable route leaks among them, restart frr and all instance received correct RD and RT values. Checked 'show bgp vrf all ipv4 unicast route-leak' and vpn table 'show bgp ipv4 vpn all' output. Signed-off-by: Chirag Shah --- bgpd/bgp_mplsvpn.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_mplsvpn.h | 1 + bgpd/bgpd.c | 4 ++ 3 files changed, 124 insertions(+) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 765170d1a5..fdfd42bf30 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1483,6 +1483,97 @@ static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name) } } +/* This API is used during router-id change, reflect VPNs + * auto RD and RT values and readvertise routes to VPN table. + */ +void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw) +{ + afi_t afi; + int debug; + char *vname; + const char *export_name; + char buf[RD_ADDRSTRLEN]; + struct bgp *bgp_import; + struct listnode *node; + struct ecommunity *ecom; + vpn_policy_direction_t idir, edir; + + if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT + && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + return; + + export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME; + debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | + BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); + + idir = BGP_VPN_POLICY_DIR_FROMVPN; + edir = BGP_VPN_POLICY_DIR_TOVPN; + + for (afi = 0; afi < AFI_MAX; ++afi) { + if (!vpn_leak_to_vpn_active(bgp, afi, NULL)) + continue; + + if (withdraw) { + vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, + afi, bgp_get_default(), bgp); + if (debug) + zlog_debug("%s: %s after to_vpn vpn_leak_prechange", + __func__, export_name); + + /* Remove import RT from VRFs */ + ecom = bgp->vpn_policy[afi].rtlist[edir]; + for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. + export_vrf, node, vname)) { + bgp_import = bgp_lookup_by_name(vname); + if (!bgp_import) + continue; + + ecommunity_del_val(bgp_import->vpn_policy[afi]. + rtlist[idir], + (struct ecommunity_val *)ecom->val); + + } + } else { + /* New router-id derive auto RD and RT and export + * to VPN + */ + form_auto_rd(bgp->router_id, bgp->vrf_rd_id, + &bgp->vrf_prd_auto); + bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto; + prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf, + sizeof(buf)); + bgp->vpn_policy[afi].rtlist[edir] = + ecommunity_str2com(buf, + ECOMMUNITY_ROUTE_TARGET, 0); + + /* Update import_vrf rt_list */ + ecom = bgp->vpn_policy[afi].rtlist[edir]; + for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. + export_vrf, node, vname)) { + bgp_import = bgp_lookup_by_name(vname); + if (!bgp_import) + continue; + if (bgp_import->vpn_policy[afi].rtlist[idir]) + bgp_import->vpn_policy[afi].rtlist[idir] + = ecommunity_merge( + bgp_import->vpn_policy[afi] + .rtlist[idir], ecom); + else + bgp_import->vpn_policy[afi].rtlist[idir] + = ecommunity_dup(ecom); + + } + /* Update routes to VPN */ + vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, + afi, bgp_get_default(), + bgp); + if (debug) + zlog_debug("%s: %s after to_vpn vpn_leak_postchange", + __func__, export_name); + } + } +} + void vpn_policy_routemap_event(const char *rmap_name) { int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT); @@ -1508,11 +1599,15 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, char buf[1000]; struct ecommunity *ecom; bool first_export = false; + int debug; export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; idir = BGP_VPN_POLICY_DIR_FROMVPN; edir = BGP_VPN_POLICY_DIR_TOVPN; + debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | + BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); + /* * Cross-ref both VRFs. Also, note if this is the first time * any VRF is importing from "import_vrf". @@ -1555,6 +1650,23 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom); SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT); + if (debug) { + const char *from_name; + + from_name = from_bgp->name ? from_bgp->name : + VRF_DEFAULT_NAME; + zlog_debug("%s from %s to %s first_export %u import-rt %s export-rt %s", + __func__, from_name, export_name, first_export, + to_bgp->vpn_policy[afi].rtlist[idir] ? + (ecommunity_ecom2str(to_bgp->vpn_policy[afi]. + rtlist[idir], + ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " ", + to_bgp->vpn_policy[afi].rtlist[edir] ? + (ecommunity_ecom2str(to_bgp->vpn_policy[afi]. + rtlist[edir], + ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " "); + } + /* Does "import_vrf" first need to export its routes or that * is already done and we just need to import those routes * from the global table? @@ -1573,12 +1685,16 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, char *vname; struct ecommunity *ecom; struct listnode *node; + int debug; export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; idir = BGP_VPN_POLICY_DIR_FROMVPN; edir = BGP_VPN_POLICY_DIR_TOVPN; + debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | + BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); + /* Were we importing from "import_vrf"? */ for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node, vname)) { @@ -1596,6 +1712,9 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, if (!vname) return; + if (debug) + zlog_debug("%s from %s to %s", __func__, tmp_name, export_name); + /* Remove "import_vrf" from our import list. */ listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname); XFREE(MTYPE_TMP, vname); diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 5b989e1853..1962d39243 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -231,5 +231,6 @@ extern void vpn_policy_routemap_event(const char *rmap_name); extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey); extern void vpn_leak_postchange_all(void); +extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw); #endif /* _QUAGGA_BGP_MPLSVPN_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a200424561..23e7802dab 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -253,6 +253,8 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id) if (is_evpn_enabled()) bgp_evpn_handle_router_id_update(bgp, TRUE); + vpn_handle_router_id_update(bgp, TRUE); + IPV4_ADDR_COPY(&bgp->router_id, id); /* Set all peer's local identifier with this value. */ @@ -270,6 +272,8 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id) if (is_evpn_enabled()) bgp_evpn_handle_router_id_update(bgp, FALSE); + vpn_handle_router_id_update(bgp, FALSE); + return 0; }