From: vivek Date: Mon, 27 Aug 2018 22:13:30 +0000 (+0000) Subject: Merge remote-tracking branch 'upstream/master' into evpn-extended-mobility X-Git-Tag: frr-7.1-dev~395^2~1 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=f190902f523abaa1035cbbb385387bc6c72dd1dc;p=mirror%2Ffrr.git Merge remote-tracking branch 'upstream/master' into evpn-extended-mobility Conflicts: zebra/zebra_vxlan.c --- f190902f523abaa1035cbbb385387bc6c72dd1dc diff --cc zebra/zebra_vxlan.c index 79c2bb03e6,b0fc0a39bd..9dfbfe6ce2 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@@ -1963,14 -1963,11 +1965,15 @@@ static int zvni_local_neigh_update(zebr char buf2[INET6_ADDRSTRLEN]; zebra_neigh_t *n = NULL; zebra_mac_t *zmac = NULL, *old_zmac = NULL; + uint32_t old_mac_seq = 0, mac_new_seq = 0; + bool upd_mac_seq = false; + bool neigh_mac_change = false; + bool check_rbit = false; - /* create a dummy MAC if the MAC is not already present */ + /* Check if the MAC exists. */ zmac = zvni_mac_lookup(zvni, macaddr); if (!zmac) { + /* create a dummy MAC if the MAC is not already present */ if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "AUTO MAC %s created for neigh %s on VNI %u", @@@ -1988,79 -1985,53 +1991,89 @@@ memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info)); memset(&zmac->flags, 0, sizeof(uint32_t)); SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); + } else { + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { + /* + * We don't change the MAC to local upon a neighbor + * learn event, we wait for the explicit local MAC + * learn. However, we have to compute its sequence + * number in preparation for when it actually turns + * local. + */ + upd_mac_seq = true; + } } - /* If same entry already exists, it might be a change or it might be a - * move from remote to local. - */ + /* Check if the neighbor exists. */ n = zvni_neigh_lookup(zvni, ip); - if (n) { + if (!n) { + /* New neighbor - create */ + n = zvni_neigh_add(zvni, ip, macaddr); + if (!n) { + flog_err( + ZEBRA_ERR_MAC_ADD_FAILED, + "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", + ipaddr2str(ip, buf2, sizeof(buf2)), + prefix_mac2str(macaddr, buf, sizeof(buf)), + ifp->name, ifp->ifindex, zvni->vni); + return -1; + } + /* Set "local" forwarding info. */ + SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + n->ifindex = ifp->ifindex; ++ check_rbit = true; + } else { if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { - + /* If there is no MAC change, BGP isn't interested. */ + if (router_flag != + (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) + ? 1 : 0)) + check_rbit = true; + if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0) { /* Update any params and return - client doesn't * care about a purely local change. */ n->ifindex = ifp->ifindex; - return 0; - } + } else { - /* If the MAC has changed, need to issue a delete - * first as this means a different MACIP route. - * Also, need to do some unlinking/relinking. - * We also need to update the MAC's sequence number - * in different situations. - */ - if (IS_ZEBRA_NEIGH_ACTIVE(n)) - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, - &n->emac, 0); - old_zmac = zvni_mac_lookup(zvni, &n->emac); - if (old_zmac) { - old_mac_seq = CHECK_FLAG(old_zmac->flags, - ZEBRA_MAC_REMOTE) ? - old_zmac->rem_seq : old_zmac->loc_seq; - neigh_mac_change = upd_mac_seq = true; - listnode_delete(old_zmac->neigh_list, n); - zvni_deref_ip2mac(zvni, old_zmac, 0); - } - /* If the MAC has changed, - * need to issue a delete first - * as this means a different MACIP route. - * Also, need to do some unlinking/relinking. ++ /* If the MAC has changed, need to issue a ++ * delete first as this means a different ++ * MACIP route. Also, need to do some ++ * unlinking/relinking. We also need to ++ * update the MAC's sequence number ++ * in different situations. + */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, - &n->emac, 0); ++ if (IS_ZEBRA_NEIGH_ACTIVE(n)) ++ zvni_neigh_send_del_to_client( ++ zvni->vni, &n->ip, &n->emac, 0); + old_zmac = zvni_mac_lookup(zvni, &n->emac); + if (old_zmac) { - listnode_delete(old_zmac->neigh_list, n); ++ old_mac_seq = ++ CHECK_FLAG(old_zmac->flags, ++ ZEBRA_MAC_REMOTE) ? ++ old_zmac->rem_seq : ++ old_zmac->loc_seq; ++ neigh_mac_change = upd_mac_seq = true; ++ listnode_delete( ++ old_zmac->neigh_list, n); + zvni_deref_ip2mac(zvni, old_zmac, 0); + } - /* Update the forwarding info. */ - n->ifindex = ifp->ifindex; - memcpy(&n->emac, macaddr, ETH_ALEN); + /* Update the forwarding info. */ + n->ifindex = ifp->ifindex; + memcpy(&n->emac, macaddr, ETH_ALEN); - /* Link to new MAC */ - listnode_add_sort(zmac->neigh_list, n); + /* Link to new MAC */ + listnode_add_sort(zmac->neigh_list, n); + } - } else - /* Neighbor has moved from remote to local. */ - { - /* If MAC has changed, do the unlink/link */ + } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { + /* + * Neighbor has moved from remote to local. Its + * MAC could have also changed as part of the move. + */ if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) != 0) { old_zmac = zvni_mac_lookup(zvni, &n->emac); @@@ -2086,50 -2051,53 +2099,57 @@@ n->r_vtep_ip.s_addr = 0; SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); n->ifindex = ifp->ifindex; + check_rbit = true; } - } else { - /* New neighbor - create */ - n = zvni_neigh_add(zvni, ip, macaddr); - if (!n) { - flog_err( - ZEBRA_ERR_MAC_ADD_FAILED, - "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, zvni->vni); - return -1; - } - /* Set "local" forwarding info. */ - SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - n->ifindex = ifp->ifindex; - check_rbit = true; + } + + /* If MAC was previously remote, or the neighbor had a different + * MAC earlier, recompute the sequence number. + */ + if (upd_mac_seq) { + uint32_t seq1, seq2; + + seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ? + zmac->rem_seq + 1 : zmac->loc_seq; + seq2 = neigh_mac_change ? old_mac_seq + 1 : 0; + mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ? + MAX(seq1, seq2) : zmac->loc_seq; } + /*Mark Router flag (R-bit) */ + if (router_flag) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + else + UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + /* Before we program this in BGP, we need to check if MAC is locally - * learnt as well + * learnt. If not, force neighbor to be inactive and reset its seq. */ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Skipping neigh %s add to client as MAC %s is not local on VNI %u with flags 0x%x", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni, n->flags); - + ZEBRA_NEIGH_SET_INACTIVE(n); + n->loc_seq = 0; + zmac->loc_seq = mac_new_seq; return 0; } - /* Set router flag (R-bit) */ - if (router_flag) - SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + if (!check_rbit) { ++ return 0; ++ } + + /* If the MAC's sequence number has changed, inform the MAC and all + * neighbors associated with the MAC to BGP, else just inform this + * neighbor. + */ + if (upd_mac_seq && zmac->loc_seq != mac_new_seq) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Skipping neigh %s with MAC %s on VNI %u add to client as router flag is not set.", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni); + zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u", + prefix_mac2str(macaddr, buf, sizeof(buf)), + zvni->vni, zmac->loc_seq, mac_new_seq); + zmac->loc_seq = mac_new_seq; + if (zvni_mac_send_add_to_client(zvni->vni, macaddr, + zmac->flags, zmac->loc_seq)) + return -1; + zvni_process_neigh_on_local_mac_change(zvni, zmac, 1); return 0; } @@@ -4002,440 -3976,73 +4024,446 @@@ static int zebra_vxlan_readd_remote_rma return 0; } -/* Public functions */ - -int is_l3vni_for_prefix_routes_only(vni_t vni) +/* Process a remote MACIP add from BGP. */ +static void process_remote_macip_add(vni_t vni, + struct ethaddr *macaddr, + uint16_t ipa_len, + struct ipaddr *ipaddr, + uint8_t flags, + uint32_t seq, + struct in_addr vtep_ip) { - zebra_l3vni_t *zl3vni = NULL; - - zl3vni = zl3vni_lookup(vni); - if (!zl3vni) - return 0; - - return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0; -} + zebra_vni_t *zvni; + zebra_vtep_t *zvtep; + zebra_mac_t *mac, *old_mac; + zebra_neigh_t *n = NULL; + int update_mac = 0, update_neigh = 0; + char buf[ETHER_ADDR_STRLEN]; + char buf1[INET6_ADDRSTRLEN]; + struct interface *ifp = NULL; + struct zebra_if *zif = NULL; + uint32_t tmp_seq; + uint8_t sticky = 0; + u_char remote_gw = 0; ++ uint8_t router_flag = 0; -/* handle evpn route in vrf table */ -void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac, - struct ipaddr *vtep_ip, - struct prefix *host_prefix) -{ - zebra_l3vni_t *zl3vni = NULL; - struct ipaddr ipv4_vtep; + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup(vni); + if (!zvni) { + zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni); + return; + } - zl3vni = zl3vni_from_vrf(vrf_id); - if (!zl3vni || !is_l3vni_oper_up(zl3vni)) + ifp = zvni->vxlan_if; + if (ifp) + zif = ifp->info; + if (!ifp || + !if_is_operative(ifp) || + !zif || + !zif->brslave_info.br_if) { + zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info", + vni); return; + } - /* - * add the next hop neighbor - - * neigh to be installed is the ipv6 nexthop neigh + /* The remote VTEP specified should normally exist, but it is + * possible that when peering comes up, peer may advertise MACIP + * routes before advertising type-3 routes. */ - zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); + zvtep = zvni_vtep_find(zvni, &vtep_ip); + if (!zvtep) { + if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { + flog_err( + ZEBRA_ERR_VTEP_ADD_FAILED, + "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD", + vni, zvni); + return; + } - /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(struct ipaddr)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); + zvni_vtep_install(zvni, &vtep_ip); + } - /* - * add the rmac - remote rmac to be installed is against the ipv4 - * nexthop address - */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix); -} + sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); ++ router_flag = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); -/* handle evpn vrf route delete */ -void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, - struct ipaddr *vtep_ip, - struct prefix *host_prefix) -{ - zebra_l3vni_t *zl3vni = NULL; - zebra_neigh_t *nh = NULL; - zebra_mac_t *zrmac = NULL; + mac = zvni_mac_lookup(zvni, macaddr); - zl3vni = zl3vni_from_vrf(vrf_id); - if (!zl3vni) + /* Ignore 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("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", + vni, + prefix_mac2str(macaddr, buf, sizeof(buf)), + ipa_len ? " IP " : "", + ipa_len ? + ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); return; + } - /* find the next hop entry and rmac entry */ - nh = zl3vni_nh_lookup(zl3vni, vtep_ip); + /* 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 + || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0) + != remote_gw + || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) + || seq != mac->rem_seq) + update_mac = 1; + + if (update_mac) { + if (!mac) { + mac = zvni_mac_add(zvni, macaddr); + if (!mac) { + zlog_warn( + "Failed to add MAC %s VNI %u Remote VTEP %s", + prefix_mac2str(macaddr, buf, + sizeof(buf)), + vni, inet_ntoa(vtep_ip)); + return; + } + + /* Is this MAC created for a MACIP? */ + if (ipa_len) + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + } else { + const char *mac_type; + + /* When host moves but changes its (MAC,IP) + * binding, BGP may install a MACIP entry that + * corresponds to "older" location of the host + * in transient situations (because {IP1,M1} + * is a different route from {IP1,M2}). Check + * the sequence number and ignore this update + * if appropriate. + */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + tmp_seq = mac->loc_seq; + mac_type = "local"; + } else { + tmp_seq = mac->rem_seq; + mac_type = "remote"; + } + if (seq < tmp_seq) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u", + vni, + prefix_mac2str(macaddr, + buf, sizeof(buf)), + ipa_len ? " IP " : "", + ipa_len ? + ipaddr2str(ipaddr, + buf1, sizeof(buf1)) : "", + mac_type, + tmp_seq); + return; + } + } + + /* Set "auto" and "remote" forwarding info. */ + UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); + mac->fwd_info.r_vtep_ip = vtep_ip; + + if (sticky) + SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + else + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + + if (remote_gw) + SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); + else + UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); + + zvni_process_neigh_on_remote_mac_add(zvni, mac); + + /* Install the entry. */ + zvni_mac_install(zvni, mac); + } + + /* Update seq number. */ + mac->rem_seq = seq; + + /* If there is no IP, return after clearing AUTO flag of MAC. */ + if (!ipa_len) { + UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + return; + } + + /* Check if the remote neighbor itself is unknown or has a + * change. If so, create or update and then install the entry. + */ + n = zvni_neigh_lookup(zvni, ipaddr); + if (!n + || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) + || (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) + || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip) ++ || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0) ++ != router_flag) + || seq != n->rem_seq) + update_neigh = 1; + + if (update_neigh) { + if (!n) { + n = zvni_neigh_add(zvni, ipaddr, macaddr); + if (!n) { + zlog_warn( + "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", + ipaddr2str(ipaddr, buf1, + sizeof(buf1)), + prefix_mac2str(macaddr, buf, + sizeof(buf)), + vni, inet_ntoa(vtep_ip)); + return; + } + + } else { + const char *n_type; + + /* When host moves but changes its (MAC,IP) + * binding, BGP may install a MACIP entry that + * corresponds to "older" location of the host + * in transient situations (because {IP1,M1} + * is a different route from {IP1,M2}). Check + * the sequence number and ignore this update + * if appropriate. + */ + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + tmp_seq = n->loc_seq; + n_type = "local"; + } else { + tmp_seq = n->rem_seq; + n_type = "remote"; + } + if (seq < tmp_seq) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u", + vni, + prefix_mac2str(macaddr, + buf, sizeof(buf)), + ipa_len ? " IP " : "", + ipa_len ? + ipaddr2str(ipaddr, + buf1, sizeof(buf1)) : "", + n_type, + tmp_seq); + return; + } + if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) { + /* MAC change, send a delete for old + * neigh if learnt locally. + */ + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) && + IS_ZEBRA_NEIGH_ACTIVE(n)) + zvni_neigh_send_del_to_client( + zvni->vni, &n->ip, + &n->emac, 0); + + /* update neigh list for macs */ + old_mac = zvni_mac_lookup(zvni, &n->emac); + if (old_mac) { + listnode_delete(old_mac->neigh_list, n); + zvni_deref_ip2mac(zvni, old_mac, 1); + } + listnode_add_sort(mac->neigh_list, n); + memcpy(&n->emac, macaddr, ETH_ALEN); + } + } + + /* Set "remote" forwarding info. */ + UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + n->r_vtep_ip = vtep_ip; + SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); + + /* Set router flag (R-bit) to this Neighbor entry */ + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); ++ else ++ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + + /* Install the entry. */ + zvni_neigh_install(zvni, n); + } + + /* Update seq number. */ + n->rem_seq = seq; +} + +/* Process a remote MACIP delete from BGP. */ +static void process_remote_macip_del(vni_t vni, + struct ethaddr *macaddr, + uint16_t ipa_len, + struct ipaddr *ipaddr, + struct in_addr vtep_ip) +{ + zebra_vni_t *zvni; + zebra_mac_t *mac = NULL; + zebra_neigh_t *n = NULL; + struct interface *ifp = NULL; + struct zebra_if *zif = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf1[INET6_ADDRSTRLEN]; + + /* Locate VNI hash entry - expected to exist. */ + zvni = zvni_lookup(vni); + if (!zvni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni); + return; + } + + ifp = zvni->vxlan_if; + if (ifp) + zif = ifp->info; + if (!ifp || + !if_is_operative(ifp) || + !zif || + !zif->brslave_info.br_if) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info", + vni); + return; + } + + /* The remote VTEP specified is normally expected to exist, but + * it is possible that the peer may delete the VTEP before deleting + * any MACs referring to the VTEP, in which case the handler (see + * remote_vtep_del) would have already deleted the MACs. + */ + if (!zvni_vtep_find(zvni, &vtep_ip)) + return; + + mac = zvni_mac_lookup(zvni, macaddr); + if (ipa_len) + n = zvni_neigh_lookup(zvni, ipaddr); + + if (n && !mac) { + zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL", + prefix_mac2str(macaddr, buf, sizeof(buf)), + ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni); + return; + } + + /* If the remote mac or neighbor doesn't exist there is nothing + * more to do. Otherwise, uninstall the entry and then remove it. + */ + if (!mac && !n) + return; + + /* 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_warn( + "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", + vni, + prefix_mac2str(macaddr, buf, sizeof(buf)), + ipa_len ? " IP " : "", + ipa_len ? + ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); + return; + } + + /* Uninstall remote neighbor or MAC. */ + if (n) { + /* When the MAC changes for an IP, it is possible the + * client may update the new MAC before trying to delete the + * "old" neighbor (as these are two different MACIP routes). + * Do the delete only if the MAC matches. + */ + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) + && (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) { + zvni_neigh_uninstall(zvni, n); + zvni_neigh_del(zvni, n); + zvni_deref_ip2mac(zvni, mac, 1); + } + } else { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + zvni_process_neigh_on_remote_mac_del(zvni, mac); + + if (list_isempty(mac->neigh_list)) { + zvni_mac_uninstall(zvni, mac, 0); + zvni_mac_del(zvni, mac); + } else + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + } + } +} + + +/* Public functions */ + +int is_l3vni_for_prefix_routes_only(vni_t vni) +{ + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) + return 0; + + return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0; +} + +/* handle evpn route in vrf table */ +void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac, + struct ipaddr *vtep_ip, + struct prefix *host_prefix) +{ + zebra_l3vni_t *zl3vni = NULL; + struct ipaddr ipv4_vtep; + + zl3vni = zl3vni_from_vrf(vrf_id); + if (!zl3vni || !is_l3vni_oper_up(zl3vni)) + return; + + /* + * add the next hop neighbor - + * neigh to be installed is the ipv6 nexthop neigh + */ + zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); + + /* + * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 + * address. Rmac is programmed against the ipv4 vtep because we only + * support ipv4 tunnels in the h/w right now + */ + memset(&ipv4_vtep, 0, sizeof(struct ipaddr)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, + sizeof(struct in_addr)); + + /* + * add the rmac - remote rmac to be installed is against the ipv4 + * nexthop address + */ + zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix); +} + +/* handle evpn vrf route delete */ +void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, + struct ipaddr *vtep_ip, + struct prefix *host_prefix) +{ + zebra_l3vni_t *zl3vni = NULL; + zebra_neigh_t *nh = NULL; + zebra_mac_t *zrmac = NULL; + + zl3vni = zl3vni_from_vrf(vrf_id); + if (!zl3vni) + return; + + /* find the next hop entry and rmac entry */ + nh = zl3vni_nh_lookup(zl3vni, vtep_ip); if (!nh) return; zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac); @@@ -5511,18 -5226,181 +5540,17 @@@ void zebra_vxlan_remote_macip_add(ZAPI_ if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s", + "Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s", + vni, prefix_mac2str(&macaddr, buf, sizeof(buf)), - ipaddr2str(&ip, buf1, sizeof(buf1)), vni, - inet_ntoa(vtep_ip), flags, + ipa_len ? " IP " : "", + ipa_len ? + ipaddr2str(&ip, buf1, sizeof(buf1)) : "", + flags, seq, inet_ntoa(vtep_ip), zebra_route_string(client->proto)); - /* Locate VNI hash entry - expected to exist. */ - zvni = zvni_lookup(vni); - if (!zvni) { - zlog_warn( - "Failed to locate VNI hash upon remote MACIP ADD, VNI %u", - vni); - continue; - } - ifp = zvni->vxlan_if; - if (!ifp) { - zlog_warn( - "VNI %u hash %p doesn't have intf upon remote MACIP add", - vni, zvni); - continue; - } - zif = ifp->info; - - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - continue; - - /* The remote VTEP specified should normally exist, but it is - * possible - * that when peering comes up, peer may advertise MACIP routes - * before - * advertising type-3 routes. - */ - zvtep = zvni_vtep_find(zvni, &vtep_ip); - if (!zvtep) { - if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { - flog_err( - ZEBRA_ERR_VTEP_ADD_FAILED, - "Failed to add remote VTEP, VNI %u zvni %p", - vni, zvni); - continue; - } - - zvni_vtep_install(zvni, &vtep_ip); - } - - 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 - || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0) - != remote_gw - || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) - update_mac = 1; - - if (update_mac) { - if (!mac) { - mac = zvni_mac_add(zvni, &macaddr); - if (!mac) { - zlog_warn( - "Failed to add MAC %s VNI %u Remote VTEP %s", - prefix_mac2str(&macaddr, buf, - sizeof(buf)), - vni, inet_ntoa(vtep_ip)); - return; - } - - /* Is this MAC created for a MACIP? */ - if (ipa_len) - SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - } - - /* Set "auto" and "remote" forwarding info. */ - UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); - SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); - mac->fwd_info.r_vtep_ip = vtep_ip; - - if (sticky) - SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); - else - UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); - - if (remote_gw) - SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); - else - UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); - - zvni_process_neigh_on_remote_mac_add(zvni, mac); - - /* Install the entry. */ - zvni_mac_install(zvni, mac); - } - - /* If there is no IP, continue - after clearing AUTO flag of - * MAC. */ - if (!ipa_len) { - UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - continue; - } - - /* Check if the remote neighbor itself is unknown or has a - * change. - * If so, create or update and then install the entry. - */ - n = zvni_neigh_lookup(zvni, &ip); - if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) - || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0) - != router_flag) - || (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0) - || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)) - update_neigh = 1; - - if (update_neigh) { - if (!n) { - n = zvni_neigh_add(zvni, &ip, &macaddr); - if (!n) { - zlog_warn( - "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", - ipaddr2str(&ip, buf1, - sizeof(buf1)), - prefix_mac2str(&macaddr, buf, - sizeof(buf)), - vni, inet_ntoa(vtep_ip)); - return; - } - - } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr)) - != 0) { - /* MAC change, update neigh list for old and new - * mac */ - old_mac = zvni_mac_lookup(zvni, &n->emac); - if (old_mac) { - listnode_delete(old_mac->neigh_list, n); - zvni_deref_ip2mac(zvni, old_mac, 1); - } - listnode_add_sort(mac->neigh_list, n); - memcpy(&n->emac, &macaddr, ETH_ALEN); - } - - /* Set "remote" forwarding info. */ - UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - /* TODO: Handle MAC change. */ - n->r_vtep_ip = vtep_ip; - SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); - - /* Set router flag (R-bit) to this Neighbor entry */ - if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) - SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); - else - UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); -- - /* Install the entry. */ - zvni_neigh_install(zvni, n); - } + process_remote_macip_add(vni, &macaddr, ipa_len, &ip, + flags, seq, vtep_ip); } stream_failure: