diff options
Diffstat (limited to 'zebra/zebra_vxlan.c')
| -rw-r--r-- | zebra/zebra_vxlan.c | 223 |
1 files changed, 124 insertions, 99 deletions
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 469aceafb9..ea0bef3718 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -153,7 +153,7 @@ static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); -static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local); +static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac); static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt); static unsigned int vni_hash_keymake(void *p); @@ -180,8 +180,8 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, struct ipaddr *ip); struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); static int advertise_gw_macip_enabled(zebra_vni_t *zvni); -static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, - int uninstall); +static int remote_neigh_count(zebra_mac_t *zmac); +static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac); /* Private functions */ static int host_rb_entry_compare(const struct host_rb_entry *hle1, @@ -1876,7 +1876,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, /* see if the mac needs to be deleted as well*/ if (mac) - zvni_deref_ip2mac(zvni, mac, 0); + zvni_deref_ip2mac(zvni, mac); return 0; } @@ -1963,7 +1963,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, struct interface *ifp, struct ipaddr *ip, struct ethaddr *macaddr, - uint8_t router_flag) + bool is_router) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -2028,51 +2028,60 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, 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. - */ + bool mac_different; + bool cur_is_router; + + /* Note any changes and see if of interest to BGP. */ + mac_different = (memcmp(n->emac.octet, + macaddr->octet, ETH_ALEN) != 0) ? 1 : 0; + cur_is_router = !!CHECK_FLAG(n->flags, + ZEBRA_NEIGH_ROUTER_FLAG); + if (!mac_different && is_router == cur_is_router) { n->ifindex = ifp->ifindex; - } else { + return 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. 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 (!mac_different) { + /* Only the router flag has changed. */ + if (is_router) + SET_FLAG(n->flags, + ZEBRA_NEIGH_ROUTER_FLAG); + else + UNSET_FLAG(n->flags, + ZEBRA_NEIGH_ROUTER_FLAG); - /* Update the forwarding info. */ - n->ifindex = ifp->ifindex; - memcpy(&n->emac, macaddr, ETH_ALEN); + if (IS_ZEBRA_NEIGH_ACTIVE(n)) + return zvni_neigh_send_add_to_client( + zvni->vni, ip, macaddr, + n->flags, n->loc_seq); + return 0; + } - /* Link to new MAC */ - listnode_add_sort(zmac->neigh_list, n); + /* 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); } + /* 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); } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { /* * Neighbor has moved from remote to local. Its @@ -2090,7 +2099,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, neigh_mac_change = upd_mac_seq = true; listnode_delete(old_zmac->neigh_list, n); - zvni_deref_ip2mac(zvni, old_zmac, 0); + zvni_deref_ip2mac(zvni, old_zmac); } /* Link to new MAC */ @@ -2121,7 +2130,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, } /*Mark Router flag (R-bit) */ - if (router_flag) + if (is_router) SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); else UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); @@ -2309,7 +2318,7 @@ static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) } if (wctx->uninstall) - zvni_mac_uninstall(wctx->zvni, mac, 0); + zvni_mac_uninstall(wctx->zvni, mac); zvni_mac_del(wctx->zvni, mac); } @@ -2593,7 +2602,7 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) { struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; - uint8_t sticky; + bool sticky; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -2603,26 +2612,24 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) return -1; vxl = &zif->l2info.vxl; - sticky = CHECK_FLAG(mac->flags, - (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)) ? 1 : 0; + sticky = !!CHECK_FLAG(mac->flags, + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky); } /* - * Uninstall remote MAC from the kernel. In the scenario where the MAC - * moves to remote, we have to uninstall any existing local entry first. + * Uninstall remote MAC from the kernel. */ -static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local) +static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) { struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; - struct in_addr vtep_ip = {.s_addr = 0}; - struct zebra_ns *zns; + struct in_addr vtep_ip; struct interface *ifp; - if (!local && !(mac->flags & ZEBRA_MAC_REMOTE)) + if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; if (!zvni->vxlan_if) { @@ -2636,19 +2643,10 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local) return -1; vxl = &zif->l2info.vxl; - if (local) { - zns = zebra_ns_lookup(NS_DEFAULT); - ifp = if_lookup_by_index_per_ns(zns, - mac->fwd_info.local.ifindex); - if (!ifp) // unexpected - return -1; - } else { - ifp = zvni->vxlan_if; - vtep_ip = mac->fwd_info.r_vtep_ip; - } + ifp = zvni->vxlan_if; + vtep_ip = mac->fwd_info.r_vtep_ip; - return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip, - local); + return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); } /* @@ -2666,20 +2664,43 @@ static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) } /* + * Count of remote neighbors referencing this MAC. + */ +static int remote_neigh_count(zebra_mac_t *zmac) +{ + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; + int count = 0; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) + count++; + } + + return count; +} + +/* * Decrement neighbor refcount of MAC; uninstall and free it if * appropriate. */ -static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, - int uninstall) +static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac) { - if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) - || !list_isempty(mac->neigh_list)) + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) return; - if (uninstall) - zvni_mac_uninstall(zvni, mac, 0); + /* If all remote neighbors referencing a remote MAC go away, + * we need to uninstall the MAC. + */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + remote_neigh_count(mac) == 0) { + zvni_mac_uninstall(zvni, mac); + UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); + } - zvni_mac_del(zvni, mac); + /* If no neighbors, delete the MAC. */ + if (list_isempty(mac->neigh_list)) + zvni_mac_del(zvni, mac); } /* @@ -3290,7 +3311,7 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) vxl = &zif->l2info.vxl; return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan, - &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); + &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); } /* handle rmac add */ @@ -4046,9 +4067,9 @@ static void process_remote_macip_add(vni_t vni, struct interface *ifp = NULL; struct zebra_if *zif = NULL; uint32_t tmp_seq; - uint8_t sticky = 0; - uint8_t remote_gw = 0; - uint8_t router_flag = 0; + bool sticky; + bool remote_gw; + bool is_router; /* Locate VNI hash entry - expected to exist. */ zvni = zvni_lookup(vni); @@ -4086,9 +4107,9 @@ static void process_remote_macip_add(vni_t vni, zvni_vtep_install(zvni, &vtep_ip); } - 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); + sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); mac = zvni_mac_lookup(zvni, macaddr); @@ -4112,9 +4133,8 @@ static void process_remote_macip_add(vni_t vni, */ 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 + || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) + || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) || seq != mac->rem_seq) update_mac = 1; @@ -4205,10 +4225,9 @@ static void process_remote_macip_add(vni_t vni, n = zvni_neigh_lookup(zvni, ipaddr); if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) + || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) || (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; @@ -4272,7 +4291,7 @@ static void process_remote_macip_add(vni_t vni, 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); + zvni_deref_ip2mac(zvni, old_mac); } listnode_add_sort(mac->neigh_list, n); memcpy(&n->emac, macaddr, ETH_ALEN); @@ -4384,16 +4403,22 @@ static void process_remote_macip_del(vni_t vni, && (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); + zvni_deref_ip2mac(zvni, mac); } } 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); + /* If all remote neighbors referencing a remote MAC + * go away, we need to uninstall the MAC. + */ + if (remote_neigh_count(mac) == 0) { + zvni_mac_uninstall(zvni, mac); + UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); + } + if (list_isempty(mac->neigh_list)) zvni_mac_del(zvni, mac); - } else + else SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } } @@ -5388,8 +5413,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, struct ipaddr *ip, struct ethaddr *macaddr, uint16_t state, - uint8_t ext_learned, - uint8_t router_flag) + bool is_ext, + bool is_router) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -5415,14 +5440,14 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u", ipaddr2str(ip, buf2, sizeof(buf2)), prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, state, ext_learned ? "ext-learned " : "", - router_flag ? "router " : "", + ifp->ifindex, state, is_ext ? "ext-learned " : "", + is_router ? "router " : "", zvni->vni); /* Is this about a local neighbor or a remote one? */ - if (!ext_learned) + if (!is_ext) return zvni_local_neigh_update(zvni, ifp, ip, macaddr, - router_flag); + is_router); return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state); } @@ -5735,7 +5760,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, int zebra_vxlan_local_mac_add_update(struct interface *ifp, struct interface *br_if, struct ethaddr *macaddr, vlanid_t vid, - uint8_t sticky) + bool sticky) { zebra_vni_t *zvni; zebra_mac_t *mac; |
