From ead40654de7260c0b66061a41da1aac0c4febef7 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 13 Nov 2017 03:19:52 -0800 Subject: [PATCH] bgpd/zebra/lib: Add Default Gateway extended community 1. Added default gw extended community 2. code modification to handle sticky-mac/default-gw-mac as they go together 3. show command support for newly added extended community 4. State in zebra to reflect if a mac/neigh is default gateway 5. show command enhancement to refelect the same in zebra commands Ticket: CM-17428 Review: CCR-6580 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_attr.c | 3 + bgpd/bgp_attr.h | 3 + bgpd/bgp_attr_evpn.c | 30 +++++++ bgpd/bgp_attr_evpn.h | 1 + bgpd/bgp_ecommunity.c | 3 + bgpd/bgp_evpn.c | 103 +++++++++++++++++++--- bgpd/bgp_evpn_private.h | 7 ++ lib/zclient.h | 4 +- zebra/zebra_vxlan.c | 164 ++++++++++++++++++++++++------------ zebra/zebra_vxlan_private.h | 2 + 10 files changed, 248 insertions(+), 72 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 206d91bfe9..f197ad16a3 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1876,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); attr->sticky = sticky; + /* Check if this is a Gateway MAC-IP advertisement */ + attr->default_gw = bgp_attr_default_gw(attr); + /* Extract the Rmac, if any */ bgp_attr_rmac(attr, &attr->rmac); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1de1bee0f9..ebe14a7ceb 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -162,6 +162,9 @@ struct attr { /* Static MAC for EVPN */ u_char sticky; + /* Flag for default gateway extended community in EVPN */ + u_char default_gw; + /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index eaa4e329d4..e74fa5a2be 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -134,6 +134,36 @@ void bgp_attr_rmac(struct attr *attr, } } +/* + * return true if attr contains default gw extended community + */ +uint8_t bgp_attr_default_gw(struct attr *attr) +{ + struct ecommunity *ecom; + int i; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return 0; + + /* If there is a default gw extendd community return true otherwise + * return 0 */ + for (i = 0; i < ecom->size; i++) { + u_char *pnt; + u_char type, sub_type; + + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + + if ((type == ECOMMUNITY_ENCODE_OPAQUE + && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) + return 1; + } + + return 0; +} + /* * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 8b55cb3002..a211da8d2f 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -62,5 +62,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, u_char *sticky); +extern uint8_t bgp_attr_default_gw(struct attr *attr); #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 9caf38d569..7dafde51a1 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -690,6 +690,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) tunneltype = ntohs(tunneltype); len = sprintf(str_buf + str_pnt, "ET:%d", tunneltype); + } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) { + len = sprintf(str_buf + str_pnt, + "Default Gateway"); } else unk_ecom = 1; } else if (type == ECOMMUNITY_ENCODE_EVPN) { diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 12cc425bd3..3e74e48793 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -506,7 +506,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn) static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, struct prefix_evpn *p, struct in_addr remote_vtep_ip, int add, - u_char sticky) + u_char flags) { struct stream *s; int ipa_len; @@ -541,18 +541,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, } stream_put_in_addr(s, &remote_vtep_ip); - /* TX MAC sticky status */ + /* TX flags - MAC sticky status and/or gateway mac */ if (add) - stream_putc(s, sticky); + stream_putc(s, flags); stream_putw_at(s, 0, stream_get_endp(s)); if (bgp_debug_zebra(NULL)) - zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s", + zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s", add ? "ADD" : "DEL", vpn->vni, - sticky ? "sticky " : "", prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)), ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)), + flags, inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); @@ -662,9 +662,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, { struct ecommunity ecom_encap; struct ecommunity ecom_sticky; + struct ecommunity ecom_default_gw; struct ecommunity ecom_rmac; struct ecommunity_val eval; struct ecommunity_val eval_sticky; + struct ecommunity_val eval_default_gw; struct ecommunity_val eval_rmac; bgp_encap_types tnl_type; struct listnode *node, *nnode; @@ -719,6 +721,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, &ecom_rmac); } + if (attr->default_gw) { + memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + encode_default_gw_extcomm(&eval_default_gw); + ecom_default_gw.size = 1; + ecom_default_gw.val = (uint8_t *)eval_default_gw.val; + attr->ecommunity = ecommunity_merge(attr->ecommunity, + &ecom_default_gw); + } + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -776,13 +787,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) /* Install EVPN route into zebra. */ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, struct prefix_evpn *p, - struct in_addr remote_vtep_ip, u_char sticky) + struct in_addr remote_vtep_ip, u_char flags) { int ret; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, - 1, sticky); + 1, flags); else ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1); @@ -853,6 +864,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; + u_char flags = 0; /* Compute the best path. */ bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new, @@ -870,11 +882,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && !bgp->addpath_tx_used[afi][safi]) { - if (bgp_zebra_has_route_changed(rn, old_select)) + if (bgp_zebra_has_route_changed(rn, old_select)) { + if (old_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (old_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, old_select->attr->nexthop, - old_select->attr->sticky); + flags); + } UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(rn); return ret; @@ -899,9 +916,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_NORMAL) { + flags = 0; + if (new_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (new_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, new_select->attr->nexthop, - new_select->attr->sticky); + flags); /* If an old best existed and it was a "local" route, the only * reason * it would be supplanted is due to MAC mobility procedures. So, @@ -931,6 +953,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, return ret; } +/* + * Return true if the local ri for this rn is of type gateway mac + */ +static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn) +{ + struct bgp_info *tmp_ri = NULL; + struct bgp_info *local_ri = NULL; + + local_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + } + + if (!local_ri) + return 0; + + return local_ri->attr->default_gw; +} + /* * Return true if the local ri for this rn has sticky set @@ -1129,7 +1173,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * SVI) advertised in EVPN. * This will ensure that local routes are preferred for g/w macs */ - if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) { + if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { u_int32_t cur_seqnum; /* Add MM extended community to route. */ @@ -1206,7 +1250,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); bgpevpn_get_rmac(vpn, &attr.rmac); vni2label(vpn->vni, &(attr.label)); @@ -1394,22 +1439,27 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) struct bgp_info *ri; struct attr attr; struct attr attr_sticky; + struct attr attr_def_gw; struct attr attr_ip6; struct attr attr_sticky_ip6; + struct attr attr_def_gw_ip6; struct attr *attr_new; afi = AFI_L2VPN; safi = SAFI_EVPN; memset(&attr, 0, sizeof(struct attr)); memset(&attr_sticky, 0, sizeof(struct attr)); + memset(&attr_def_gw, 0, sizeof(struct attr)); memset(&attr_ip6, 0, sizeof(struct attr)); memset(&attr_sticky_ip6, 0, sizeof(struct attr)); + memset(&attr_def_gw_ip6, 0, sizeof(struct attr)); /* Build path-attribute - all type-2 routes for this VNI will share the * same path attribute. */ bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP); + bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP); attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; @@ -1419,6 +1469,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_sticky.sticky = 1; bgpevpn_get_rmac(vpn, &attr_sticky.rmac); + attr_def_gw.nexthop = vpn->originator_ip; + attr_def_gw.mp_nexthop_global_in = vpn->originator_ip; + attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_def_gw.default_gw = 1; + bgpevpn_get_rmac(vpn, &attr_def_gw.rmac); bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP); attr_ip6.nexthop = vpn->originator_ip; @@ -1430,12 +1485,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_sticky_ip6.sticky = 1; bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac); + attr_def_gw_ip6.nexthop = vpn->originator_ip; + attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip; + attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_def_gw_ip6.default_gw = 1; + bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac); /* Set up RT, ENCAP and sticky MAC extended community. */ build_evpn_route_extcomm(vpn, &attr, AFI_IP); build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP); + build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP); build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6); build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6); + build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP); /* Walk this VNI's route table and update local type-2 routes. For any * routes updated, update corresponding entry in the global table too. @@ -1454,6 +1516,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri, 0); + else if (evpn_route_is_def_gw(bgp, rn)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_def_gw, 0, 1, + &ri, 0); else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri, 0); @@ -1462,6 +1528,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky_ip6, 0, 1, &ri, 0); + else if (evpn_route_is_def_gw(bgp, rn)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_def_gw_ip6, 0, 1, + &ri, 0); else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_ip6, 0, 1, @@ -1496,7 +1566,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Unintern temporary. */ aspath_unintern(&attr.aspath); + aspath_unintern(&attr_ip6.aspath); aspath_unintern(&attr_sticky.aspath); + aspath_unintern(&attr_sticky_ip6.aspath); + aspath_unintern(&attr_def_gw.aspath); + aspath_unintern(&attr_def_gw_ip6.aspath); return 0; } @@ -4042,12 +4116,13 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, char buf2[INET6_ADDRSTRLEN]; zlog_err( - "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s", + "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)", bgp->vrf_id, vpn->vni, CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway" : "", prefix_mac2str(mac, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2))); + ipaddr2str(ip, buf2, sizeof(buf2)), + flags); return -1; } diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 2d52e1995d..f5a0998f62 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -257,6 +257,13 @@ static inline void encode_rmac_extcomm(struct ecommunity_val *eval, memcpy(&eval->val[2], rmac, ETH_ALEN); } +static inline void encode_default_gw_extcomm(struct ecommunity_val *eval) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE; + eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW; +} + static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq, struct ecommunity_val *eval) { diff --git a/lib/zclient.h b/lib/zclient.h index c24f2b2a4e..892e0ea994 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -343,8 +343,8 @@ enum zapi_route_notify_owner { }; /* Zebra MAC types */ -#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/ -#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/ +#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ +#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ struct zclient_options { bool receive_notify; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1690079f68..1d70e970ec 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -286,6 +286,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) : "Inactive"); } } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) { + if (!json) + vty_out(vty, " Default-gateway"); + else + json_object_boolean_true_add(json, "defaultGateway"); + } if (json == NULL) vty_out(vty, "\n"); } @@ -534,6 +540,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) vty_out(vty, " Auto Mac "); } + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) + vty_out(vty, " Sticky Mac "); + + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) + vty_out(vty, " Default-gateway Mac "); + vty_out(vty, "\n"); /* print all the associated neigh */ vty_out(vty, " Neighbors:\n"); @@ -1409,7 +1421,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni, ZEBRA_NEIGH_SET_ACTIVE(n); zvni_neigh_send_add_to_client( - zvni->vni, &n->ip, &n->emac, 0); + zvni->vni, &n->ip, &n->emac, n->flags); } else { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( @@ -1519,8 +1531,14 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni, */ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char neigh_flags) { + u_char flags = 0; + + if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, ZEBRA_MACIP_ADD); } @@ -1729,6 +1747,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.vid = vxl->access_vlan; @@ -1748,9 +1767,14 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; + /* Only advertise in BGP if the knob is enabled */ + if (!advertise_gw_macip_enabled(zvni)) + return 0; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP", @@ -1759,7 +1783,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, ipaddr2str(ip, buf2, sizeof(buf2))); zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, - ZEBRA_MAC_TYPE_GW); + n->flags); return 0; } @@ -1793,16 +1817,21 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) return -1; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP", - ifp->name, ifp->ifindex, zvni->vni, - prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2))); - - /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - ZEBRA_MAC_TYPE_GW); + /* only need to delete the entry from bgp if we sent it before */ + if (advertise_gw_macip_enabled(zvni)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + ifp->vrf_id, ifp->name, + ifp->ifindex, zvni->vni, + prefix_mac2str(&(n->emac), + NULL, + ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); + + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, + ZEBRA_MACIP_TYPE_GW); + } /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -1869,9 +1898,6 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, if (!zvni) return; - if (!advertise_gw_macip_enabled(zvni)) - return; - ifp = zvni->vxlan_if; if (!ifp) return; @@ -1985,7 +2011,6 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) { struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = backet->data; - u_char sticky = 0; if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || ((wctx->flags & DEL_REMOTE_MAC) @@ -1995,11 +2020,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 - : 0; zvni_mac_send_del_to_client( wctx->zvni->vni, &mac->macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + mac->flags); } if (wctx->uninstall) @@ -2074,8 +2097,16 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) * Inform BGP about local MAC addition. */ static int zvni_mac_send_add_to_client(vni_t vni, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char mac_flags) { + u_char flags = 0; + + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, ZEBRA_MACIP_ADD); } @@ -2084,8 +2115,16 @@ static int zvni_mac_send_add_to_client(vni_t vni, * Inform BGP about local MAC deletion. */ static int zvni_mac_send_del_to_client(vni_t vni, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char mac_flags) { + u_char flags = 0; + + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, ZEBRA_MACIP_DEL); } @@ -2393,15 +2432,13 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni, vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (vlan_if) { - if (advertise_gw_macip_enabled(zvni)) { - /* Add SVI MAC-IP */ - zvni_add_macip_for_intf(vlan_if, zvni); + /* Add SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); - /* Add VRR MAC-IP - if any*/ - vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); - if (vrr_if) - zvni_add_macip_for_intf(vrr_if, zvni); - } + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); neigh_read_for_vlan(zns, vlan_if); } @@ -4768,7 +4805,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, zvni->vni); ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0); + return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); } @@ -4879,6 +4916,17 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, if (!mac && !n) continue; + /* Ignore the delete if this mac is a gateway mac-ip */ + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { + zlog_err("%u: Ignore Del for MAC %s neigh %s on VNI %u as it is configured as a default gateway", + zvrf_id(zvrf), + prefix_mac2str(&macaddr, buf, sizeof(buf)), + ipaddr2str(&ip, buf1, sizeof(buf1)), + vni); + continue; + } + /* Uninstall remote neighbor or MAC. */ if (n) { /* When the MAC changes for an IP, it is possible the @@ -4936,7 +4984,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, int update_mac = 0, update_neigh = 0; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; - u_char sticky; + u_char sticky = 0; + u_char flags = 0; struct interface *ifp = NULL; struct zebra_if *zif = NULL; @@ -4973,17 +5022,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); l += IPV4_MAX_BYTELEN; - /* Get 'sticky' flag. */ - STREAM_GETC(s, sticky); + /* Get flags - sticky mac and/or gateway mac */ + flags = stream_getc(s); + sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); l++; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s", - sticky ? "sticky " : "", + "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s", prefix_mac2str(&macaddr, buf, sizeof(buf)), ipaddr2str(&ip, buf1, sizeof(buf1)), vni, - inet_ntoa(vtep_ip), + inet_ntoa(vtep_ip), flags, zebra_route_string(client->proto)); /* Locate VNI hash entry - expected to exist. */ @@ -5025,13 +5074,26 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, zvni_vtep_install(zvni, &vtep_ip); } - /* First, check if the remote MAC is unknown or has a change. If - * so, - * that needs to be updated first. Note that client could - * install - * MAC and MACIP separately or just install the latter. - */ mac = zvni_mac_lookup(zvni, &macaddr); + + /* Ignore the update if the mac is already present + as a gateway mac */ + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) && + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac", + zvrf_id(zvrf), + prefix_mac2str(&macaddr, + buf, sizeof(buf)), + ipaddr2str(&ip, buf1, + sizeof(buf1)), vni); + continue; + } + + /* check if the remote MAC is unknown or has a change. + * If so, that needs to be updated first. Note that client could + * install MAC and MACIP separately or just install the latter. + */ if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0) != sticky @@ -5146,7 +5208,6 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, zebra_vni_t *zvni; zebra_mac_t *mac; char buf[ETHER_ADDR_STRLEN]; - u_char sticky; zif = ifp->info; assert(zif); @@ -5178,9 +5239,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, ifp->name, ifp->ifindex, vni); /* Remove MAC from BGP. */ - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvni->vni, macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); /* * If there are no neigh associated with the mac delete the mac @@ -5253,7 +5312,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zebra_vni_t *zvni; zebra_mac_t *mac; char buf[ETHER_ADDR_STRLEN]; - u_char sticky; /* We are interested in MACs only on ports or (port, VLAN) that * map to a VNI. @@ -5282,9 +5340,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return 0; /* Remove MAC from BGP. */ - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvni->vni, macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); @@ -5423,7 +5479,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (add) { zvni_process_neigh_on_local_mac_add(zvni, mac); return zvni_mac_send_add_to_client(zvni->vni, macaddr, - sticky); + mac->flags); } return 0; @@ -5687,10 +5743,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, } - /* check if we are advertising gw macip routes */ - if (!advertise_gw_macip_enabled(zvni)) - return 0; - memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); if (p->family == AF_INET) { diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index ef6f9b99cb..ecbdbfd835 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -233,6 +233,7 @@ struct zebra_mac_t_ { #define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ #define ZEBRA_MAC_STICKY 0x08 /* Static MAC */ #define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */ +#define ZEBRA_MAC_DEF_GW 0x20 /* Local or remote info. */ union { @@ -314,6 +315,7 @@ struct zebra_neigh_t_ { #define ZEBRA_NEIGH_LOCAL 0x01 #define ZEBRA_NEIGH_REMOTE 0x02 #define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */ +#define ZEBRA_NEIGH_DEF_GW 0x08 enum zebra_neigh_state state; -- 2.39.5