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",
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);
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;
}
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);
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: