diff options
| -rw-r--r-- | zebra/subdir.am | 1 | ||||
| -rw-r--r-- | zebra/zebra_evpn.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mac.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mh.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_evpn_neigh.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_l2.c | 5 | ||||
| -rw-r--r-- | zebra/zebra_nb_state.c | 1 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 505 | ||||
| -rw-r--r-- | zebra/zebra_vxlan_if.c | 554 | ||||
| -rw-r--r-- | zebra/zebra_vxlan_if.h | 55 | ||||
| -rw-r--r-- | zebra/zebra_vxlan_private.h | 2 |
11 files changed, 621 insertions, 510 deletions
diff --git a/zebra/subdir.am b/zebra/subdir.am index 5c4a87b934..104980218d 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -105,6 +105,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_vrf.c \ zebra/zebra_vty.c \ zebra/zebra_vxlan.c \ + zebra/zebra_vxlan_if.c \ zebra/zebra_evpn_mh.c \ zebra/zebra_neigh.c \ zebra/zserv.c \ diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 0bf6039693..6f2765284b 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -47,10 +47,10 @@ #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" #include "zebra/zebra_evpn_neigh.h" -#include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_evpn_vxlan.h" #include "zebra/zebra_router.h" diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 4babbe97cd..801403c11c 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -36,6 +36,8 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_vrf.h" +#include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_evpn_mac.h" diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 9d672ab51d..a2a0952165 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -44,9 +44,9 @@ #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" -#include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_router.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_nhg.h" diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 684720bb4d..4c7f393fa1 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -36,6 +36,8 @@ #include "zebra/rt.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_vrf.h" +#include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_evpn_neigh.h" diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 550b819428..e1de9a147a 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -43,6 +43,7 @@ #include "zebra/interface.h" #include "zebra/zebra_l2.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" #include "zebra/zebra_evpn_mh.h" /* definitions */ @@ -349,8 +350,6 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp, if (add) { memcpy(&zif->l2info.vxl, vxlan_info, sizeof(*vxlan_info)); - zebra_evpn_vl_vxl_ref(zif->l2info.vxl.vni_info.vni.access_vlan, - zif->l2info.vxl.vni_info.vni.vni, zif); zebra_vxlan_if_add(ifp); return; } @@ -415,8 +414,6 @@ void zebra_l2_vxlanif_del(struct interface *ifp) zif = ifp->info; assert(zif); - zebra_evpn_vl_vxl_deref(zif->l2info.vxl.vni_info.vni.access_vlan, - zif->l2info.vxl.vni_info.vni.vni, zif); zebra_vxlan_if_del(ifp); } diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index 0c0bd56383..45b9d440a6 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -26,6 +26,7 @@ #include "zebra/debug.h" #include "printfrr.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" /* * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/up-count diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 79f696c97d..28ffafec5a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -907,7 +907,7 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) return tmp_if; } -static int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn) +int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn) { zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */); @@ -4797,509 +4797,6 @@ void zebra_vxlan_macvlan_up(struct interface *ifp) } } -/* - * Handle VxLAN interface down - */ -int zebra_vxlan_if_down(struct interface *ifp) -{ - vni_t vni; - struct zebra_if *zif = NULL; - struct zebra_l3vni *zl3vni = NULL; - struct zebra_evpn *zevpn; - struct zebra_vxlan_vni *vnip; - - /* Check if EVPN is enabled. */ - if (!is_evpn_enabled()) - return 0; - - zif = ifp->info; - assert(zif); - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - /* process-if-down for l3-vni */ - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, - ifp->ifindex, vni); - - zebra_vxlan_process_l3vni_oper_down(zl3vni); - } else { - /* process if-down for l2-vni */ - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, - ifp->ifindex, vni); - - /* Locate hash entry; it is expected to exist. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - zlog_debug( - "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - - assert(zevpn->vxlan_if == ifp); - - /* remove from l3-vni list */ - zl3vni = zl3vni_from_vrf(zevpn->vrf_id); - if (zl3vni) - listnode_delete(zl3vni->l2vnis, zevpn); - - /* Delete this VNI from BGP. */ - zebra_evpn_send_del_to_client(zevpn); - - /* Free up all neighbors and MACs, if any. */ - zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); - zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); - - /* Free up all remote VTEPs, if any. */ - zebra_evpn_vtep_del_all(zevpn, 1); - } - return 0; -} - -/* - * Handle VxLAN interface up - update BGP if required. - */ -int zebra_vxlan_if_up(struct interface *ifp) -{ - vni_t vni; - struct zebra_if *zif = NULL; - struct zebra_evpn *zevpn = NULL; - struct zebra_l3vni *zl3vni = NULL; - struct zebra_vxlan_vni *vnip; - - /* Check if EVPN is enabled. */ - if (!is_evpn_enabled()) - return 0; - - zif = ifp->info; - assert(zif); - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - /* we need to associate with SVI, if any, we can associate with - * svi-if only after association with vxlan-intf is complete - */ - zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); - zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s" - , ifp->name, ifp->ifindex, vni, - zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", - zl3vni->mac_vlan_if ? - zl3vni->mac_vlan_if->name : "NIL"); - - if (is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up(zl3vni); - } else { - /* Handle L2-VNI add */ - struct interface *vlan_if = NULL; - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name, - ifp->ifindex, vni); - - /* Locate hash entry; it is expected to exist. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - zlog_debug( - "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - - assert(zevpn->vxlan_if == ifp); - vlan_if = zvni_map_to_svi(vnip->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); - if (zl3vni) - listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); - } - - /* If part of a bridge, inform BGP about this VNI. */ - /* Also, read and populate local MACs and neighbors. */ - if (zif->brslave_info.br_if) { - zebra_evpn_send_add_to_client(zevpn); - zebra_evpn_read_mac_neigh(zevpn, ifp); - } - } - - return 0; -} - -/* - * Handle VxLAN interface delete. Locate and remove entry in hash table - * and update BGP, if required. - */ -int zebra_vxlan_if_del(struct interface *ifp) -{ - vni_t vni; - struct zebra_if *zif = NULL; - struct zebra_evpn *zevpn = NULL; - struct zebra_l3vni *zl3vni = NULL; - struct zebra_vxlan_vni *vnip; - - /* Check if EVPN is enabled. */ - if (!is_evpn_enabled()) - return 0; - - zif = ifp->info; - assert(zif); - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, - ifp->ifindex); - - /* process oper-down for l3-vni */ - zebra_vxlan_process_l3vni_oper_down(zl3vni); - - /* remove the association with vxlan_if */ - memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr)); - zl3vni->vxlan_if = NULL; - } else { - - /* process if-del for l2-vni*/ - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, - ifp->ifindex); - - /* Locate hash entry; it is expected to exist. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - zlog_debug( - "Failed to locate VNI hash at del, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return 0; - } - - /* remove from l3-vni list */ - zl3vni = zl3vni_from_vrf(zevpn->vrf_id); - if (zl3vni) - listnode_delete(zl3vni->l2vnis, zevpn); - /* Delete VNI from BGP. */ - zebra_evpn_send_del_to_client(zevpn); - - /* Free up all neighbors and MAC, if any. */ - zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH); - zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC); - - /* Free up all remote VTEPs, if any. */ - zebra_evpn_vtep_del_all(zevpn, 0); - - /* Delete the hash entry. */ - if (zebra_evpn_vxlan_del(zevpn)) { - flog_err(EC_ZEBRA_VNI_DEL_FAILED, - "Failed to del EVPN hash %p, IF %s(%u) VNI %u", - zevpn, ifp->name, ifp->ifindex, zevpn->vni); - return -1; - } - } - return 0; -} - -/* - * Handle VxLAN interface update - change to tunnel IP, master or VLAN. - */ -int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) -{ - vni_t vni; - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; - struct zebra_evpn *zevpn = NULL; - struct zebra_l3vni *zl3vni = NULL; - struct interface *vlan_if = NULL; - struct zebra_vxlan_vni *vnip; - - /* Check if EVPN is enabled. */ - if (!is_evpn_enabled()) - return 0; - - zif = ifp->info; - assert(zif); - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", - vni, ifp->name, ifp->ifindex, vnip->access_vlan, - &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, - chgflags); - - /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) - && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { - zebra_vxlan_process_l3vni_oper_down(zl3vni); - return 0; - } - - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) - && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { - zebra_vxlan_process_l3vni_oper_down(zl3vni); - zebra_vxlan_process_l3vni_oper_up(zl3vni); - return 0; - } - - /* access-vlan change - process oper down, associate with new - * svi_if and then process oper up again - */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { - if (if_is_operative(ifp)) { - zebra_vxlan_process_l3vni_oper_down(zl3vni); - zl3vni->svi_if = NULL; - zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); - zl3vni->mac_vlan_if = - zl3vni_map_to_mac_vlan_if(zl3vni); - zl3vni->local_vtep_ip = vxl->vtep_ip; - if (is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up( - zl3vni); - } - } - - /* - * local-ip change - process oper down, associate with new - * local-ip and then process oper up again - */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { - if (if_is_operative(ifp)) { - zebra_vxlan_process_l3vni_oper_down(zl3vni); - zl3vni->local_vtep_ip = vxl->vtep_ip; - if (is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up( - zl3vni); - } - } - - /* Update local tunnel IP. */ - zl3vni->local_vtep_ip = vxl->vtep_ip; - - /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { - if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up(zl3vni); - } - } else { - - /* Update VNI hash. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - zlog_debug( - "Failed to find EVPN hash on update, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", - vni, ifp->name, ifp->ifindex, vnip->access_vlan, - &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, - chgflags); - - /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) - && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { - /* Delete from client, remove all remote VTEPs */ - /* Also, free up all MACs and neighbors. */ - zevpn->svi_if = NULL; - zebra_evpn_send_del_to_client(zevpn); - zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); - zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); - zebra_evpn_vtep_del_all(zevpn, 1); - return 0; - } - - /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { - /* Remove all existing local neigh and MACs for this VNI - * (including from BGP) - */ - zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); - zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); - } - - if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr - || zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { - zebra_vxlan_sg_deref(zevpn->local_vtep_ip, - zevpn->mcast_grp); - zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); - zevpn->local_vtep_ip = vxl->vtep_ip; - zevpn->mcast_grp = vnip->mcast_grp; - /* on local vtep-ip check if ES orig-ip - * needs to be updated - */ - zebra_evpn_es_set_base_evpn(zevpn); - } - zevpn_vxlan_if_set(zevpn, ifp, true /* set */); - vlan_if = zvni_map_to_svi(vnip->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); - if (zl3vni) - listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); - } - - /* Take further actions needed. - * Note that if we are here, there is a change of interest. - */ - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - return 0; - - /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) - zebra_evpn_send_add_to_client(zevpn); - - /* If there is a valid new master or a VLAN mapping change, - * read and populate local MACs and neighbors. - * Also, reinstall any remote MACs and neighbors - * for this VNI (based on new VLAN). - */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) - zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { - struct mac_walk_ctx m_wctx; - struct neigh_walk_ctx n_wctx; - - zebra_evpn_read_mac_neigh(zevpn, ifp); - - memset(&m_wctx, 0, sizeof(m_wctx)); - m_wctx.zevpn = zevpn; - hash_iterate(zevpn->mac_table, - zebra_evpn_install_mac_hash, &m_wctx); - - memset(&n_wctx, 0, sizeof(n_wctx)); - n_wctx.zevpn = zevpn; - hash_iterate(zevpn->neigh_table, - zebra_evpn_install_neigh_hash, &n_wctx); - } - } - - return 0; -} - -/* - * Handle VxLAN interface add. - */ -int zebra_vxlan_if_add(struct interface *ifp) -{ - vni_t vni; - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; - struct zebra_evpn *zevpn = NULL; - struct zebra_l3vni *zl3vni = NULL; - struct zebra_vxlan_vni *vnip; - - /* Check if EVPN is enabled. */ - if (!is_evpn_enabled()) - return 0; - - zif = ifp->info; - assert(zif); - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; - - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - - /* process if-add for l3-vni*/ - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u", - vni, ifp->name, ifp->ifindex, vnip->access_vlan, - &vxl->vtep_ip, - zif->brslave_info.bridge_ifindex); - - /* associate with vxlan_if */ - zl3vni->local_vtep_ip = vxl->vtep_ip; - zl3vni->vxlan_if = ifp; - - /* Associate with SVI, if any. We can associate with svi-if only - * after association with vxlan_if is complete */ - zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); - - zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); - - if (is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up(zl3vni); - } else { - - /* process if-add for l2-vni */ - struct interface *vlan_if = NULL; - - /* Create or update EVPN hash. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) - zevpn = zebra_evpn_add(vni); - - if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr - || zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { - zebra_vxlan_sg_deref(zevpn->local_vtep_ip, - zevpn->mcast_grp); - zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); - zevpn->local_vtep_ip = vxl->vtep_ip; - zevpn->mcast_grp = vnip->mcast_grp; - /* on local vtep-ip check if ES orig-ip - * needs to be updated - */ - zebra_evpn_es_set_base_evpn(zevpn); - } - zevpn_vxlan_if_set(zevpn, ifp, true /* set */); - vlan_if = zvni_map_to_svi(vnip->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); - if (zl3vni) - listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); - } - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u", - vni, - vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME, - ifp->name, ifp->ifindex, vnip->access_vlan, - &vxl->vtep_ip, &vnip->mcast_grp, - zif->brslave_info.bridge_ifindex); - - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - return 0; - - /* Inform BGP */ - zebra_evpn_send_add_to_client(zevpn); - - /* Read and populate local MACs and neighbors */ - zebra_evpn_read_mac_neigh(zevpn, ifp); - } - - return 0; -} - int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, char *err, int err_str_sz, int filter, int add) diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c new file mode 100644 index 0000000000..eb01547fcc --- /dev/null +++ b/zebra/zebra_vxlan_if.c @@ -0,0 +1,554 @@ +/* + * Zebra EVPN for VxLAN interface handling + * + * Copyright (C) 2020 Cumulus Networks, Inc. + * Vivek Venkatraman, Stephen Worley, Sharath Ramamurthy + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <zebra.h> + +#include "hash.h" +#include "if.h" +#include "jhash.h" +#include "linklist.h" +#include "log.h" +#include "memory.h" +#include "prefix.h" +#include "stream.h" +#include "table.h" +#include "vlan.h" +#include "vxlan.h" +#ifdef GNU_LINUX +#include <linux/neighbour.h> +#endif + +#include "zebra/zebra_router.h" +#include "zebra/debug.h" +#include "zebra/interface.h" +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/rt_netlink.h" +#include "zebra/zebra_errors.h" +#include "zebra/zebra_l2.h" +#include "zebra/zebra_ns.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" +#include "zebra/zebra_evpn.h" +#include "zebra/zebra_evpn_mac.h" +#include "zebra/zebra_evpn_neigh.h" +#include "zebra/zebra_vxlan_private.h" +#include "zebra/zebra_evpn_mh.h" +#include "zebra/zebra_evpn_vxlan.h" +#include "zebra/zebra_router.h" + +/* + * Handle VxLAN interface down + */ +int zebra_vxlan_if_down(struct interface *ifp) +{ + vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l3vni *zl3vni = NULL; + struct zebra_evpn *zevpn; + struct zebra_vxlan_vni *vnip; + + /* Check if EVPN is enabled. */ + if (!is_evpn_enabled()) + return 0; + + zif = ifp->info; + assert(zif); + vnip = zebra_vxlan_if_vni_find(zif, 0); + vni = vnip->vni; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + /* process-if-down for l3-vni */ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, + ifp->ifindex, vni); + + zebra_vxlan_process_l3vni_oper_down(zl3vni); + } else { + /* process if-down for l2-vni */ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, + ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + zlog_debug( + "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + assert(zevpn->vxlan_if == ifp); + + /* remove from l3-vni list */ + zl3vni = zl3vni_from_vrf(zevpn->vrf_id); + if (zl3vni) + listnode_delete(zl3vni->l2vnis, zevpn); + + /* Delete this VNI from BGP. */ + zebra_evpn_send_del_to_client(zevpn); + + /* Free up all neighbors and MACs, if any. */ + zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); + zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); + + /* Free up all remote VTEPs, if any. */ + zebra_evpn_vtep_del_all(zevpn, 1); + } + return 0; +} + +/* + * Handle VxLAN interface up - update BGP if required. + */ +int zebra_vxlan_if_up(struct interface *ifp) +{ + vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_evpn *zevpn = NULL; + struct zebra_l3vni *zl3vni = NULL; + struct zebra_vxlan_vni *vnip; + + /* Check if EVPN is enabled. */ + if (!is_evpn_enabled()) + return 0; + + zif = ifp->info; + assert(zif); + vnip = zebra_vxlan_if_vni_find(zif, 0); + vni = vnip->vni; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + /* we need to associate with SVI, if any, we can associate with + * svi-if only after association with vxlan-intf is complete + */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s", + ifp->name, ifp->ifindex, vni, + zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", + zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name + : "NIL"); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } else { + /* Handle L2-VNI add */ + struct interface *vlan_if = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name, + ifp->ifindex, vni); + + /* Locate hash entry; it is expected to exist. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + zlog_debug( + "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + assert(zevpn->vxlan_if == ifp); + vlan_if = zvni_map_to_svi(vnip->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zevpn->svi_if = vlan_if; + zevpn->vrf_id = vlan_if->vrf->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); + if (zl3vni) + listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); + } + + /* If part of a bridge, inform BGP about this VNI. */ + /* Also, read and populate local MACs and neighbors. */ + if (zif->brslave_info.br_if) { + zebra_evpn_send_add_to_client(zevpn); + zebra_evpn_read_mac_neigh(zevpn, ifp); + } + } + + return 0; +} + +/* + * Handle VxLAN interface delete. Locate and remove entry in hash table + * and update BGP, if required. + */ +int zebra_vxlan_if_del(struct interface *ifp) +{ + vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_evpn *zevpn = NULL; + struct zebra_l3vni *zl3vni = NULL; + struct zebra_vxlan_vni *vnip; + + /* Check if EVPN is enabled. */ + if (!is_evpn_enabled()) + return 0; + + zif = ifp->info; + assert(zif); + vnip = zebra_vxlan_if_vni_find(zif, 0); + vni = vnip->vni; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, + ifp->ifindex); + + /* process oper-down for l3-vni */ + zebra_vxlan_process_l3vni_oper_down(zl3vni); + + /* remove the association with vxlan_if */ + memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr)); + zl3vni->vxlan_if = NULL; + } else { + + /* process if-del for l2-vni*/ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, + ifp->ifindex); + + /* Locate hash entry; it is expected to exist. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + zlog_debug( + "Failed to locate VNI hash at del, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return 0; + } + + /* remove from l3-vni list */ + zl3vni = zl3vni_from_vrf(zevpn->vrf_id); + if (zl3vni) + listnode_delete(zl3vni->l2vnis, zevpn); + /* Delete VNI from BGP. */ + zebra_evpn_send_del_to_client(zevpn); + + /* Free up all neighbors and MAC, if any. */ + zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH); + zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC); + + /* Free up all remote VTEPs, if any. */ + zebra_evpn_vtep_del_all(zevpn, 0); + + /* Delete the hash entry. */ + if (zebra_evpn_vxlan_del(zevpn)) { + flog_err(EC_ZEBRA_VNI_DEL_FAILED, + "Failed to del EVPN hash %p, IF %s(%u) VNI %u", + zevpn, ifp->name, ifp->ifindex, zevpn->vni); + return -1; + } + } + return 0; +} + +/* + * Handle VxLAN interface update - change to tunnel IP, master or VLAN. + */ +int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) +{ + vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + struct zebra_evpn *zevpn = NULL; + struct zebra_l3vni *zl3vni = NULL; + struct interface *vlan_if = NULL; + struct zebra_vxlan_vni *vnip; + + /* Check if EVPN is enabled. */ + if (!is_evpn_enabled()) + return 0; + + zif = ifp->info; + assert(zif); + vnip = zebra_vxlan_if_vni_find(zif, 0); + vni = vnip->vni; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", + vni, ifp->name, ifp->ifindex, vnip->access_vlan, + &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, + chgflags); + + /* Removed from bridge? Cleanup and return */ + if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + return 0; + } + + if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) + && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zebra_vxlan_process_l3vni_oper_up(zl3vni); + return 0; + } + + /* access-vlan change - process oper down, associate with new + * svi_if and then process oper up again + */ + if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (if_is_operative(ifp)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni->svi_if = NULL; + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = + zl3vni_map_to_mac_vlan_if(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up( + zl3vni); + } + } + + /* + * local-ip change - process oper down, associate with new + * local-ip and then process oper up again + */ + if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (if_is_operative(ifp)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up( + zl3vni); + } + } + + /* Update local tunnel IP. */ + zl3vni->local_vtep_ip = vxl->vtep_ip; + + /* if we have a valid new master, process l3-vni oper up */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } + } else { + + /* Update VNI hash. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + zlog_debug( + "Failed to find EVPN hash on update, IF %s(%u) VNI %u", + ifp->name, ifp->ifindex, vni); + return -1; + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", + vni, ifp->name, ifp->ifindex, vnip->access_vlan, + &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, + chgflags); + + /* Removed from bridge? Cleanup and return */ + if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { + /* Delete from client, remove all remote VTEPs */ + /* Also, free up all MACs and neighbors. */ + zevpn->svi_if = NULL; + zebra_evpn_send_del_to_client(zevpn); + zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); + zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); + zebra_evpn_vtep_del_all(zevpn, 1); + return 0; + } + + /* Handle other changes. */ + if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + /* Remove all existing local neigh and MACs for this VNI + * (including from BGP) + */ + zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); + zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); + } + + if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr + || zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { + zebra_vxlan_sg_deref(zevpn->local_vtep_ip, + zevpn->mcast_grp); + zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); + zevpn->local_vtep_ip = vxl->vtep_ip; + zevpn->mcast_grp = vnip->mcast_grp; + /* on local vtep-ip check if ES orig-ip + * needs to be updated + */ + zebra_evpn_es_set_base_evpn(zevpn); + } + zevpn_vxlan_if_set(zevpn, ifp, true /* set */); + vlan_if = zvni_map_to_svi(vnip->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) + zevpn->svi_if = vlan_if; + + /* Take further actions needed. + * Note that if we are here, there is a change of interest. + */ + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; + + /* Inform BGP, if there is a change of interest. */ + if (chgflags & + (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + zebra_evpn_send_add_to_client(zevpn); + + /* If there is a valid new master or a VLAN mapping change, + * read and populate local MACs and neighbors. + * Also, reinstall any remote MACs and neighbors + * for this VNI (based on new VLAN). + */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + zebra_evpn_read_mac_neigh(zevpn, ifp); + else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + struct mac_walk_ctx m_wctx; + struct neigh_walk_ctx n_wctx; + + zebra_evpn_read_mac_neigh(zevpn, ifp); + + memset(&m_wctx, 0, sizeof(m_wctx)); + m_wctx.zevpn = zevpn; + hash_iterate(zevpn->mac_table, + zebra_evpn_install_mac_hash, &m_wctx); + + memset(&n_wctx, 0, sizeof(n_wctx)); + n_wctx.zevpn = zevpn; + hash_iterate(zevpn->neigh_table, + zebra_evpn_install_neigh_hash, &n_wctx); + } + } + + return 0; +} + +/* + * Handle VxLAN interface add. + */ +int zebra_vxlan_if_add(struct interface *ifp) +{ + vni_t vni; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + struct zebra_evpn *zevpn = NULL; + struct zebra_l3vni *zl3vni = NULL; + struct zebra_vxlan_vni *vnip; + + /* Check if EVPN is enabled. */ + if (!is_evpn_enabled()) + return 0; + + zif = ifp->info; + assert(zif); + vnip = zebra_vxlan_if_vni_find(zif, 0); + vni = vnip->vni; + + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + + /* process if-add for l3-vni*/ + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u", + vni, ifp->name, ifp->ifindex, vnip->access_vlan, + &vxl->vtep_ip, + zif->brslave_info.bridge_ifindex); + + /* associate with vxlan_if */ + zl3vni->local_vtep_ip = vxl->vtep_ip; + zl3vni->vxlan_if = ifp; + + /* Associate with SVI, if any. We can associate with svi-if only + * after association with vxlan_if is complete */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } else { + + /* process if-add for l2-vni */ + struct interface *vlan_if = NULL; + + /* Create or update EVPN hash. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) + zevpn = zebra_evpn_add(vni); + + if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr + || zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { + zebra_vxlan_sg_deref(zevpn->local_vtep_ip, + zevpn->mcast_grp); + zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); + zevpn->local_vtep_ip = vxl->vtep_ip; + zevpn->mcast_grp = vnip->mcast_grp; + /* on local vtep-ip check if ES orig-ip + * needs to be updated + */ + zebra_evpn_es_set_base_evpn(zevpn); + } + zevpn_vxlan_if_set(zevpn, ifp, true /* set */); + vlan_if = zvni_map_to_svi(vnip->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zevpn->svi_if = vlan_if; + zevpn->vrf_id = vlan_if->vrf->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); + if (zl3vni) + listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); + } + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u", + vni, + vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME, + ifp->name, ifp->ifindex, vnip->access_vlan, + &vxl->vtep_ip, &vnip->mcast_grp, + zif->brslave_info.bridge_ifindex); + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; + + /* Inform BGP */ + zebra_evpn_send_add_to_client(zevpn); + + /* Read and populate local MACs and neighbors */ + zebra_evpn_read_mac_neigh(zevpn, ifp); + } + + return 0; +} diff --git a/zebra/zebra_vxlan_if.h b/zebra/zebra_vxlan_if.h new file mode 100644 index 0000000000..721e2b87ad --- /dev/null +++ b/zebra/zebra_vxlan_if.h @@ -0,0 +1,55 @@ +/* + * Zebra VxLAN (EVPN) Data structures and definitions + * These are public definitions referenced by other files. + * Copyright (C) 2021 Cumulus Networks, Inc. + * Sharath Ramamurthy + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_VXLAN_IF_H +#define _ZEBRA_VXLAN_IF_H + +#include <zebra.h> +#include <zebra/zebra_router.h> + +#include "linklist.h" +#include "if.h" +#include "vlan.h" +#include "vxlan.h" + +#include "lib/json.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zserv.h" +#include "zebra/zebra_dplane.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int zebra_vxlan_if_down(struct interface *ifp); +extern int zebra_vxlan_if_up(struct interface *ifp); +extern int zebra_vxlan_if_del(struct interface *ifp); +extern int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags); +extern int zebra_vxlan_if_add(struct interface *ifp); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZEBRA_VXLAN_IF_H */ diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 9161348b16..6da45b214e 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -29,6 +29,7 @@ #include "if.h" #include "linklist.h" #include "zebra_vxlan.h" +#include "zebra_vxlan_if.h" #include "zebra_evpn.h" #include "zebra_evpn_mac.h" @@ -266,5 +267,6 @@ extern void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, struct in_addr mcast_grp); extern void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni); extern void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni); +extern int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn); #endif /* _ZEBRA_VXLAN_PRIVATE_H */ |
