diff --git a/zebra/main.c b/zebra/main.c index 5797a5846a..1947106750 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -55,6 +55,7 @@ #include "zebra/zebra_netns_notify.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_pbr.h" +#include "zebra/zebra_vxlan.h" #if defined(HANDLE_NETLINK_FUZZING) #include "zebra/kernel_netlink.h" @@ -455,6 +456,9 @@ int main(int argc, char **argv) /* RNH init */ zebra_rnh_init(); + /* Config handler Init */ + zebra_evpn_init(); + /* Error init */ zebra_error_init(); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 077c1ff8f0..626fa4e15f 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -224,6 +224,9 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp); static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg); +static void zvni_send_mac_to_client(zebra_vni_t *zvn); +static void zvni_send_neigh_to_client(zebra_vni_t *zvni); + /* Private functions */ static int host_rb_entry_compare(const struct host_rb_entry *hle1, const struct host_rb_entry *hle2) @@ -2869,6 +2872,16 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket, /* Add primary SVI MAC*/ zvni = (zebra_vni_t *)bucket->data; + /* Global (Zvrf) advertise-default-gw is disabled, + * but zvni advertise-default-gw is enabled + */ + if (zvni->advertise_gw_macip) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", + zvni->vni); + return; + } + ifp = zvni->vxlan_if; if (!ifp) return; @@ -2950,6 +2963,16 @@ static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket, if (!zvni) return; + /* Global(vrf) advertise-svi-ip disabled, but zvni advertise-svi-ip + * enabled + */ + if (zvni->advertise_svi_macip) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip", + zvni->vni); + return; + } + ifp = zvni->vxlan_if; if (!ifp) return; @@ -4056,46 +4079,67 @@ static void zvni_build_hash_table(void) ifp->name, ifp->ifindex, vni, inet_ntoa(vxl->vtep_ip)); - /* VNI hash entry is not expected to exist. */ + /* VNI hash entry is expected to exist, if the BGP process is killed */ zvni = zvni_lookup(vni); if (zvni) { zlog_debug( "VNI hash already present for IF %s(%u) L2-VNI %u", ifp->name, ifp->ifindex, vni); - continue; - } - zvni = zvni_add(vni); - if (!zvni) { - zlog_debug( - "Failed to add VNI hash, IF %s(%u) L2-VNI %u", - ifp->name, ifp->ifindex, vni); - return; - } + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && + zif->brslave_info.br_if) + zvni_send_add_to_client(zvni); - if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || - zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) { - zebra_vxlan_sg_deref(zvni->local_vtep_ip, - zvni->mcast_grp); - zebra_vxlan_sg_ref(vxl->vtep_ip, - vxl->mcast_grp); - zvni->local_vtep_ip = vxl->vtep_ip; - zvni->mcast_grp = vxl->mcast_grp; - } - zvni->vxlan_if = ifp; - vlan_if = zvni_map_to_svi(vxl->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zvni->vrf_id = vlan_if->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); - if (zl3vni) - listnode_add_sort(zl3vni->l2vnis, zvni); - } + /* Send Local MAC-entries to client */ + zvni_send_mac_to_client(zvni); + /* Send Loval Neighbor entries to client */ + zvni_send_neigh_to_client(zvni); + } else { + zvni = zvni_add(vni); + if (!zvni) { + zlog_debug( + "Failed to add VNI hash, IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + return; + } - /* Inform BGP if intf is up and mapped to bridge. */ - if (if_is_operative(ifp) && zif->brslave_info.br_if) - zvni_send_add_to_client(zvni); + if (zvni->local_vtep_ip.s_addr != + vxl->vtep_ip.s_addr || + zvni->mcast_grp.s_addr != + vxl->mcast_grp.s_addr) { + zebra_vxlan_sg_deref( + zvni->local_vtep_ip, + zvni->mcast_grp); + zebra_vxlan_sg_ref(vxl->vtep_ip, + vxl->mcast_grp); + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->mcast_grp = vxl->mcast_grp; + } + zvni->vxlan_if = ifp; + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zvni->vrf_id = vlan_if->vrf_id; + zl3vni = zl3vni_from_vrf( + vlan_if->vrf_id); + if (zl3vni) + listnode_add_sort( + zl3vni->l2vnis, zvni); + } + + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && + zif->brslave_info.br_if) + zvni_send_add_to_client(zvni); + } } } } @@ -8916,7 +8960,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) struct interface *ifp = NULL; if (!EVPN_ENABLED(zvrf)) { - zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u", + zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u", zvrf_id(zvrf)); return; } @@ -8927,7 +8971,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) if (!vni) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("EVPN gateway macip Adv %s, currently %s", + zlog_debug("EVPN SVI-MACIP Adv %s, currently %s", advertise ? "enabled" : "disabled", advertise_gw_macip_enabled(NULL) ? "enabled" @@ -9637,3 +9681,120 @@ static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg) zebra_vxlan_sg_del(vxlan_sg); } + +/************************** EVPN BGP config management ************************/ +/* Notify Local MACs to the clienti, skips GW MAC */ +static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket, + void *arg) +{ + struct mac_walk_ctx *wctx = arg; + zebra_mac_t *zmac = bucket->data; + + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW)) + return; + + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) + zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr, + zmac->flags, zmac->loc_seq); +} + +/* Iterator to Notify Local MACs of a L2VNI */ +static void zvni_send_mac_to_client(zebra_vni_t *zvni) +{ + struct mac_walk_ctx wctx; + + if (!zvni->mac_table) + return; + + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); + wctx.zvni = zvni; + + hash_iterate(zvni->mac_table, zvni_send_mac_hash_entry_to_client, + &wctx); +} + +/* Notify Neighbor entries to the Client, skips the GW entry */ +static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket, + void *arg) +{ + struct mac_walk_ctx *wctx = arg; + zebra_neigh_t *zn = bucket->data; + zebra_mac_t *zmac = NULL; + + if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW)) + return; + + if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) && + IS_ZEBRA_NEIGH_ACTIVE(zn)) { + zmac = zvni_mac_lookup(wctx->zvni, &zn->emac); + if (!zmac) + return; + + zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip, + &zn->emac, zn->flags, + zn->loc_seq); + } +} + +/* Iterator of a specific L2VNI */ +static void zvni_send_neigh_to_client(zebra_vni_t *zvni) +{ + struct neigh_walk_ctx wctx; + + memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); + wctx.zvni = zvni; + + hash_iterate(zvni->neigh_table, zvni_send_neigh_hash_entry_to_client, + &wctx); +} + +static void zvni_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt) +{ + zebra_vni_t *zvni = NULL; + + zvni = (zebra_vni_t *)bucket->data; + zvni->advertise_gw_macip = 0; + zvni->advertise_svi_macip = 0; + zvni->advertise_subnet = 0; + + zvni_neigh_del_all(zvni, 0, 0, + DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP); + zvni_mac_del_all(zvni, 0, 0, + DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP); + zvni_vtep_del_all(zvni, 0); +} + +/* Cleanup EVPN configuration of a specific VRF */ +static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf) +{ + zvrf->advertise_all_vni = 0; + zvrf->advertise_gw_macip = 0; + zvrf->advertise_svi_macip = 0; + zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; + + hash_iterate(zvrf->vni_table, zvni_evpn_cfg_cleanup, NULL); +} + +/* Cleanup BGP EVPN configuration upon client disconnect */ +static int zebra_evpn_cfg_clean_up(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + if (client->proto != ZEBRA_ROUTE_BGP) + return 0; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + zvrf = vrf->info; + if (zvrf) + zebra_evpn_vrf_cfg_cleanup(zvrf); + } + + return 0; +} + +/* Cleanup BGP EVPN configuration upon client disconnect */ +extern void zebra_evpn_init(void) +{ + hook_register(zserv_client_close, zebra_evpn_cfg_clean_up); +} diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index f752bdd690..6117567bc1 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -212,6 +212,7 @@ extern int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +extern void zebra_evpn_init(void); #ifdef __cplusplus }