From 5394a27663d0dbd678ebb196e7608e45aa3771dc Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Thu, 18 Apr 2019 10:17:57 +0300 Subject: [PATCH] bgpd: evpn pip data struct and cli Evpn Primary IP advertisement feature uses individual system IP and system MAC for prefix (type-5) and self type-2 routes. The PIP knob is enabled by default for bgp vrf instance. Configuration CLI for enable/disable PIP feature knob. User can configure PIP system IP and MAC to retain as permanent values. For the PIP IP, the default behavior is to accept bgp default instance's router-id. When the default instance router-id change, reflect PIP IP assignment. Reflect type-5 to use system-IP and system MAC as nexthop and RMAC values. Ticket:CM-26190 Signed-off-by: Chirag Shah --- bgpd/bgp_evpn.c | 87 +++++++++++++++++++++++-- bgpd/bgp_evpn.h | 1 + bgpd/bgp_evpn_private.h | 10 +++ bgpd/bgp_evpn_vty.c | 141 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f3c514fb15..5824a1cb56 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1543,11 +1543,44 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, memset(&attr, 0, sizeof(struct attr)); bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); } - /* Set nexthop to ourselves and fill in the Router MAC. */ - attr.nexthop = bgp_vrf->originator_ip; - attr.mp_nexthop_global_in = bgp_vrf->originator_ip; + + /* copy sys rmac */ + memcpy(&attr.rmac, &bgp_vrf->evpn_info->pip_rmac, ETH_ALEN); + /* Advertise Primary IP (PIP) is enabled, send individual + * IP (default instance router-id) as nexthop. + * PIP is disabled or vrr interface is not present + * use anycast-IP as nexthop. + */ + if (!bgp_vrf->evpn_info->advertise_pip || + (!bgp_vrf->evpn_info->is_anycast_mac)) { + attr.nexthop = bgp_vrf->originator_ip; + attr.mp_nexthop_global_in = bgp_vrf->originator_ip; + } else { + if (bgp_vrf->evpn_info->pip_ip.s_addr != INADDR_ANY) { + attr.nexthop = bgp_vrf->evpn_info->pip_ip; + attr.mp_nexthop_global_in = bgp_vrf->evpn_info->pip_ip; + } else if (bgp_vrf->evpn_info->pip_ip.s_addr == INADDR_ANY) + if (bgp_debug_zebra(NULL)) { + char buf1[PREFIX_STRLEN]; + + zlog_debug("VRF %s evp %s advertise-pip primary ip is not configured", + vrf_id_to_name(bgp_vrf->vrf_id), + prefix2str(evp, buf1, sizeof(buf1))); + } + } + + if (bgp_debug_zebra(NULL)) { + char buf[ETHER_ADDR_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("VRF %s type-5 route evp %s RMAC %s nexthop %s", + vrf_id_to_name(bgp_vrf->vrf_id), + prefix2str(evp, buf1, sizeof(buf1)), + prefix_mac2str(&attr.rmac, buf, sizeof(buf)), + inet_ntoa(attr.nexthop)); + } + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - memcpy(&attr.rmac, &bgp_vrf->rmac, sizeof(struct ethaddr)); /* Setup RT and encap extended community */ build_evpn_type5_route_extcomm(bgp_vrf, &attr); @@ -3527,8 +3560,14 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf) * update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5 * routes */ -static void update_advertise_vrf_routes(struct bgp *bgp_vrf) +void update_advertise_vrf_routes(struct bgp *bgp_vrf) { + struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */ + + bgp_evpn = bgp_get_evpn(); + if (!bgp_evpn) + return; + /* update all ipv4 routes */ if (advertise_type5_routes(bgp_vrf, AFI_IP)) bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); @@ -4586,6 +4625,9 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf, */ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) { + struct listnode *node; + struct bgp *bgp_vrf; + if (withdraw) { /* delete and withdraw all the type-5 routes @@ -4600,8 +4642,34 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) (void (*)(struct hash_bucket *, void *))withdraw_router_id_vni, bgp); + + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) { + if (bgp_vrf->evpn_info->advertise_pip && + (bgp_vrf->evpn_info->pip_ip_static.s_addr + == INADDR_ANY)) + bgp_vrf->evpn_info->pip_ip.s_addr + = INADDR_ANY; + } + } } else { + /* Assign new default instance router-id */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) { + if (bgp_vrf->evpn_info->advertise_pip && + (bgp_vrf->evpn_info->pip_ip_static.s_addr + == INADDR_ANY)) { + bgp_vrf->evpn_info->pip_ip = + bgp->router_id; + /* advertise type-5 routes with + * new nexthop + */ + update_advertise_vrf_routes(bgp_vrf); + } + } + } + /* advertise all routes in the vrf as type-5 routes with the new * RD */ @@ -6005,6 +6073,15 @@ void bgp_evpn_init(struct bgp *bgp) bgp->evpn_info->dad_freeze_time = 0; /* Initialize zebra vxlan */ bgp_zebra_dup_addr_detection(bgp); + /* Enable PIP feature by default for bgp vrf instance */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { + struct bgp *bgp_default; + + bgp->evpn_info->advertise_pip = true; + bgp_default = bgp_get_default(); + if (bgp_default) + bgp->evpn_info->pip_ip = bgp_default->router_id; + } } /* Default BUM handling is to do head-end replication. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 798c3e59bc..f9927067e5 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -192,5 +192,6 @@ extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx); extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx); +extern void update_advertise_vrf_routes(struct bgp *bgp_vrf); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f6bde2e9fa..a0c05e34f8 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -188,6 +188,16 @@ struct bgp_evpn_info { /* EVPN enable - advertise svi macip routes */ int advertise_svi_macip; + /* PIP feature knob */ + bool advertise_pip; + /* PIP IP (sys ip) */ + struct in_addr pip_ip; + struct in_addr pip_ip_static; + /* PIP MAC (sys MAC) */ + struct ethaddr pip_rmac; + struct ethaddr pip_rmac_static; + struct ethaddr pip_rmac_zebra; + bool is_anycast_mac; }; static inline int is_vrf_rd_configured(struct bgp *bgp_vrf) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 3bc8345140..882716cf37 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3650,6 +3650,129 @@ DEFUN (no_bgp_evpn_advertise_type5, return CMD_SUCCESS; } +DEFPY (bgp_evpn_advertise_pip_ip_mac, + bgp_evpn_advertise_pip_ip_mac_cmd, + "[no$no] advertise-pip [ip [mac ]]", + NO_STR + "evpn system primary IP\n" + IP_STR + "ip address\n" + MAC_STR MAC_STR MAC_STR) +{ + struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */ + struct bgp *bgp_evpn = NULL; + + if (EVPN_ENABLED(bgp_vrf)) { + vty_out(vty, + "This command is supported under L3VNI BGP EVPN VRF\n"); + return CMD_WARNING; + } + bgp_evpn = bgp_get_evpn(); + + if (!no) { + /* pip is already enabled */ + if (argc == 1 && bgp_vrf->evpn_info->advertise_pip) + return CMD_SUCCESS; + + bgp_vrf->evpn_info->advertise_pip = true; + if (ip.s_addr != INADDR_ANY) { + /* Already configured with same IP */ + if (IPV4_ADDR_SAME(&ip, + &bgp_vrf->evpn_info->pip_ip_static)) + return CMD_SUCCESS; + + bgp_vrf->evpn_info->pip_ip_static = ip; + bgp_vrf->evpn_info->pip_ip = ip; + } else { + bgp_vrf->evpn_info->pip_ip_static.s_addr + = INADDR_ANY; + /* default instance router-id assignemt */ + if (bgp_evpn) + bgp_vrf->evpn_info->pip_ip = + bgp_evpn->router_id; + } + /* parse sys mac */ + if (!is_zero_mac(&mac->eth_addr)) { + /* Already configured with same MAC */ + if (memcmp(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN) == 0) + return CMD_SUCCESS; + + memcpy(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN); + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_static, + ETH_ALEN); + } else { + /* Copy zebra sys mac */ + if (!is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_zebra)) + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_zebra, + ETH_ALEN); + } + } else { + if (argc == 2) { + if (!bgp_vrf->evpn_info->advertise_pip) + return CMD_SUCCESS; + /* Disable PIP feature */ + bgp_vrf->evpn_info->advertise_pip = false; + /* copy anycast mac */ + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->rmac, ETH_ALEN); + } else { + /* remove MAC-IP option retain PIP knob. */ + if ((ip.s_addr != INADDR_ANY) && + !IPV4_ADDR_SAME(&ip, + &bgp_vrf->evpn_info->pip_ip_static)) { + vty_out(vty, + "%% BGP EVPN PIP IP does not match\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!is_zero_mac(&mac->eth_addr) && + memcmp(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN) != 0) { + vty_out(vty, + "%% BGP EVPN PIP MAC does not match\n"); + return CMD_WARNING_CONFIG_FAILED; + } + /* pip_rmac can carry vrr_rmac reset only if it matches + * with static value. + */ + if (memcmp(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_static, + ETH_ALEN) == 0) { + /* Copy zebra sys mac */ + if (!is_zero_mac( + &bgp_vrf->evpn_info->pip_rmac_zebra)) + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_zebra, + ETH_ALEN); + else { + /* copy anycast mac */ + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->rmac, ETH_ALEN); + } + } + } + /* reset user configured sys MAC */ + memset(&bgp_vrf->evpn_info->pip_rmac_static, 0, ETH_ALEN); + /* reset user configured sys IP */ + bgp_vrf->evpn_info->pip_ip_static.s_addr = INADDR_ANY; + /* Assign default PIP IP (bgp instance router-id) */ + if (bgp_evpn) + bgp_vrf->evpn_info->pip_ip = bgp_evpn->router_id; + else + bgp_vrf->evpn_info->pip_ip.s_addr = INADDR_ANY; + } + + if (is_evpn_enabled()) { + update_advertise_vrf_routes(bgp_vrf); + } + + return CMD_SUCCESS; +} + /* * Display VNI information - for all or a specific VNI */ @@ -5457,6 +5580,23 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6)) vty_out(vty, " default-originate ipv6\n"); + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { + if (!bgp->evpn_info->advertise_pip) + vty_out(vty, " no advertise-pip\n"); + if (bgp->evpn_info->advertise_pip) { + if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY) + vty_out(vty, " advertise-pip ip %s", + inet_ntoa(bgp->evpn_info->pip_ip_static)); + if (!is_zero_mac(&(bgp->evpn_info->pip_rmac_static))) { + char buf[ETHER_ADDR_STRLEN]; + + vty_out(vty, " mac %s", + prefix_mac2str(&bgp->evpn_info->pip_rmac, + buf, sizeof(buf))); + } + vty_out(vty, "\n"); + } + } if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD)) vty_out(vty, " rd %s\n", prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1))); @@ -5527,6 +5667,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &dup_addr_detection_auto_recovery_cmd); install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_pip_ip_mac_cmd); /* test commands */ install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd); -- 2.39.5