diff options
Diffstat (limited to 'zebra/zebra_vxlan.c')
| -rw-r--r-- | zebra/zebra_vxlan.c | 388 |
1 files changed, 350 insertions, 38 deletions
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 3a8426e772..22c489e607 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -58,8 +58,19 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); +DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group"); /* definitions */ +/* PMSI strings. */ +#define VXLAN_FLOOD_STR_NO_INFO "-" +#define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO +static const struct message zvtep_flood_str[] = { + {VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO}, + {VXLAN_FLOOD_PIM_SM, "PIM-SM"}, + {VXLAN_FLOOD_HEAD_END_REPL, "HER"}, + {0} +}; + /* static function declarations */ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, @@ -167,10 +178,11 @@ static int zvni_send_del_to_client(vni_t vni); static void zvni_build_hash_table(void); static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep); static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip); -static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip); +static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip, + int flood_control); static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep); static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall); -static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip); +static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep); static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip); static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); @@ -201,6 +213,17 @@ static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, bool do_dad, bool *is_dup_detect, bool is_local); +static unsigned int zebra_vxlan_sg_hash_key_make(void *p); +static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2); +static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, + struct in_addr sip, struct in_addr mcast_grp); +static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, + struct in_addr sip, struct in_addr mcast_grp); +static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, + struct in_addr mcast_grp); +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); /* Private functions */ static int host_rb_entry_compare(const struct host_rb_entry *hle1, @@ -1858,12 +1881,16 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex); vty_out(vty, " Local VTEP IP: %s\n", inet_ntoa(zvni->local_vtep_ip)); + vty_out(vty, " Mcast group: %s\n", + inet_ntoa(zvni->mcast_grp)); } else { json_object_string_add(json, "vxlanInterface", zvni->vxlan_if->name); json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); json_object_string_add(json, "vtepIp", inet_ntoa(zvni->local_vtep_ip)); + json_object_string_add(json, "mcastGroup", + inet_ntoa(zvni->mcast_grp)); json_object_string_add(json, "advertiseGatewayMacip", zvni->advertise_gw_macip ? "Yes" : "No"); json_object_int_add(json, "numMacs", num_macs); @@ -1878,14 +1905,19 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) else json_vtep_list = json_object_new_array(); for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { - if (json == NULL) - vty_out(vty, " %s\n", - inet_ntoa(zvtep->vtep_ip)); - else { + const char *flood_str = lookup_msg(zvtep_flood_str, + zvtep->flood_control, + VXLAN_FLOOD_STR_DEFAULT); + + if (json == NULL) { + vty_out(vty, " %s flood: %s\n", + inet_ntoa(zvtep->vtep_ip), + flood_str); + } else { json_ip_str = json_object_new_string( - inet_ntoa(zvtep->vtep_ip)); + inet_ntoa(zvtep->vtep_ip)); json_object_array_add(json_vtep_list, - json_ip_str); + json_ip_str); } } if (json) @@ -3882,6 +3914,9 @@ static int zvni_del(zebra_vni_t *zvni) zvni->vxlan_if = NULL; + /* Remove references to the BUM mcast grp */ + zebra_vxlan_sg_deref(zvni->local_vtep_ip, zvni->mcast_grp); + /* Free the neighbor hash table. */ hash_free(zvni->neigh_table); zvni->neigh_table = NULL; @@ -3916,6 +3951,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) stream_putl(s, zvni->vni); stream_put_in_addr(s, &zvni->local_vtep_ip); stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ + stream_put_in_addr(s, &zvni->mcast_grp); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -4038,7 +4074,15 @@ static void zvni_build_hash_table(void) return; } - zvni->local_vtep_ip = vxl->vtep_ip; + 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); @@ -4086,13 +4130,16 @@ static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip) /* * Add remote VTEP to VNI hash table. */ -static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip) +static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip, + int flood_control) + { zebra_vtep_t *zvtep; zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t)); zvtep->vtep_ip = *vtep_ip; + zvtep->flood_control = flood_control; if (zvni->vteps) zvni->vteps->prev = zvtep; @@ -4142,12 +4189,15 @@ static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall) } /* - * Install remote VTEP into the kernel. + * Install remote VTEP into the kernel if the remote VTEP has asked + * for head-end-replication. */ -static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip) +static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep) { - if (is_vxlan_flooding_head_end()) - return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); + if (is_vxlan_flooding_head_end() && + (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) + return kernel_add_vtep(zvni->vni, zvni->vxlan_if, + &zvtep->vtep_ip); return 0; } @@ -4181,7 +4231,7 @@ static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket, for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { if (is_vxlan_flooding_head_end()) - zvni_vtep_install(zvni, &zvtep->vtep_ip); + zvni_vtep_install(zvni, zvtep); else zvni_vtep_uninstall(zvni, &zvtep->vtep_ip); } @@ -5159,7 +5209,8 @@ static void process_remote_macip_add(vni_t vni, */ zvtep = zvni_vtep_find(zvni, &vtep_ip); if (!zvtep) { - if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { + zvtep = zvni_vtep_add(zvni, &vtep_ip, VXLAN_FLOOD_DISABLED); + if (!zvtep) { flog_err( EC_ZEBRA_VTEP_ADD_FAILED, "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD", @@ -5167,7 +5218,7 @@ static void process_remote_macip_add(vni_t vni, return; } - zvni_vtep_install(zvni, &vtep_ip); + zvni_vtep_install(zvni, zvtep); } sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); @@ -7874,6 +7925,8 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) zebra_vni_t *zvni; struct interface *ifp; struct zebra_if *zif; + int flood_control; + zebra_vtep_t *zvtep; if (!is_evpn_enabled()) { zlog_debug( @@ -7895,12 +7948,13 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) STREAM_GETL(s, vni); l += 4; STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); + STREAM_GETL(s, flood_control); l += IPV4_MAX_BYTELEN; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Recv VTEP_ADD %s VNI %u from %s", - inet_ntoa(vtep_ip), vni, - zebra_route_string(client->proto)); + zlog_debug("Recv VTEP_ADD %s VNI %u flood %d from %s", + inet_ntoa(vtep_ip), vni, flood_control, + zebra_route_string(client->proto)); /* Locate VNI hash entry - expected to exist. */ zvni = zvni_lookup(vni); @@ -7927,19 +7981,31 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) if (!if_is_operative(ifp) || !zif->brslave_info.br_if) continue; - /* If the remote VTEP already exists, - there's nothing more to do. */ - if (zvni_vtep_find(zvni, &vtep_ip)) - continue; - - if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { - flog_err(EC_ZEBRA_VTEP_ADD_FAILED, - "Failed to add remote VTEP, VNI %u zvni %p", - vni, zvni); - continue; + zvtep = zvni_vtep_find(zvni, &vtep_ip); + if (zvtep) { + /* If the remote VTEP already exists check if + * the flood mode has changed + */ + if (zvtep->flood_control != flood_control) { + if (zvtep->flood_control + == VXLAN_FLOOD_DISABLED) + /* old mode was head-end-replication but + * is no longer; get rid of the HER fdb + * entry installed before + */ + zvni_vtep_uninstall(zvni, &vtep_ip); + zvtep->flood_control = flood_control; + zvni_vtep_install(zvni, zvtep); + } + } else { + zvtep = zvni_vtep_add(zvni, &vtep_ip, flood_control); + if (zvtep) + zvni_vtep_install(zvni, zvtep); + else + flog_err(EC_ZEBRA_VTEP_ADD_FAILED, + "Failed to add remote VTEP, VNI %u zvni %p", + vni, zvni); } - - zvni_vtep_install(zvni, &vtep_ip); } stream_failure: @@ -8476,7 +8542,14 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC); } - zvni->local_vtep_ip = vxl->vtep_ip; + 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; /* Take further actions needed. @@ -8488,7 +8561,9 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) /* Inform BGP, if there is a change of interest. */ if (chgflags - & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) + & (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE)) zvni_send_add_to_client(zvni); /* If there is a valid new master or a VLAN mapping change, @@ -8578,7 +8653,14 @@ int zebra_vxlan_if_add(struct interface *ifp) } } - zvni->local_vtep_ip = vxl->vtep_ip; + 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); @@ -8589,15 +8671,24 @@ int zebra_vxlan_if_add(struct interface *ifp) listnode_add_sort(zl3vni->l2vnis, zvni); } - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char addr_buf1[INET_ADDRSTRLEN]; + char addr_buf2[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &vxl->vtep_ip, + addr_buf1, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &vxl->mcast_grp, + addr_buf2, INET_ADDRSTRLEN); + zlog_debug( - "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u", + "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s mcast_grp %s master %u", vni, vlan_if ? vrf_id_to_name(vlan_if->vrf_id) : VRF_DEFAULT_NAME, ifp->name, ifp->ifindex, vxl->access_vlan, - inet_ntoa(vxl->vtep_ip), + addr_buf1, addr_buf2, 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) @@ -9144,6 +9235,8 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) return; zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp, "Zebra VRF VNI Table"); + zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make, + zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table"); } /* Cleanup VNI info, but don't free the table. */ @@ -9152,6 +9245,7 @@ void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf) if (!zvrf) return; hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); + hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL); } /* Close all VNI handling */ @@ -9311,3 +9405,221 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t) return 0; } + +/************************** vxlan SG cache management ************************/ +/* Inform PIM about the mcast group */ +static int zebra_vxlan_sg_send(struct prefix_sg *sg, + char *sg_str, uint16_t cmd) +{ + struct zserv *client = NULL; + struct stream *s = NULL; + + client = zserv_find_client(ZEBRA_ROUTE_PIM, 0); + if (!client) + return 0; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + stream_putl(s, IPV4_MAX_BYTELEN); + stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN); + stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Send %s %s to %s", + (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", sg_str, + zebra_route_string(client->proto)); + + if (cmd == ZEBRA_VXLAN_SG_ADD) + client->vxlan_sg_add_cnt++; + else + client->vxlan_sg_del_cnt++; + + return zserv_send_message(client, s); +} + +static unsigned int zebra_vxlan_sg_hash_key_make(void *p) +{ + zebra_vxlan_sg_t *vxlan_sg = p; + + return (jhash_2words(vxlan_sg->sg.src.s_addr, + vxlan_sg->sg.grp.s_addr, 0)); +} + +static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) +{ + const zebra_vxlan_sg_t *sg1 = p1; + const zebra_vxlan_sg_t *sg2 = p2; + + return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr) + && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); +} + +static zebra_vxlan_sg_t *zebra_vxlan_sg_new(struct zebra_vrf *zvrf, + struct prefix_sg *sg) +{ + zebra_vxlan_sg_t *vxlan_sg; + + vxlan_sg = XCALLOC(MTYPE_ZVXLAN_SG, sizeof(*vxlan_sg)); + + vxlan_sg->zvrf = zvrf; + vxlan_sg->sg = *sg; + prefix_sg2str(sg, vxlan_sg->sg_str); + + vxlan_sg = hash_get(zvrf->vxlan_sg_table, vxlan_sg, hash_alloc_intern); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("vxlan SG %s created", vxlan_sg->sg_str); + + return vxlan_sg; +} + +static zebra_vxlan_sg_t *zebra_vxlan_sg_find(struct zebra_vrf *zvrf, + struct prefix_sg *sg) +{ + zebra_vxlan_sg_t lookup; + + lookup.sg = *sg; + return hash_lookup(zvrf->vxlan_sg_table, &lookup); +} + +static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, + struct prefix_sg *sg) +{ + zebra_vxlan_sg_t *vxlan_sg; + zebra_vxlan_sg_t *parent = NULL; + struct in_addr sip; + + vxlan_sg = zebra_vxlan_sg_find(zvrf, sg); + if (vxlan_sg) + return vxlan_sg; + + /* create a *G entry for every BUM group implicitly - + * 1. The SG entry is used by pimd to setup the vxlan-origination-mroute + * 2. the XG entry is used by pimd to setup the + * vxlan-termination-mroute + */ + if (sg->src.s_addr) { + memset(&sip, 0, sizeof(sip)); + parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp); + if (!parent) + return NULL; + } + + vxlan_sg = zebra_vxlan_sg_new(zvrf, sg); + if (!vxlan_sg) { + if (parent) + zebra_vxlan_sg_do_deref(zvrf, sip, sg->grp); + return vxlan_sg; + } + + zebra_vxlan_sg_send(sg, vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD); + + return vxlan_sg; +} + +static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg) +{ + struct in_addr sip; + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; + + /* On SG entry deletion remove the reference to its parent XG + * entry + */ + if (vxlan_sg->sg.src.s_addr) { + memset(&sip, 0, sizeof(sip)); + zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp); + } + + zebra_vxlan_sg_send(&vxlan_sg->sg, vxlan_sg->sg_str, + ZEBRA_VXLAN_SG_DEL); + + hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VXLAN SG %s deleted", vxlan_sg->sg_str); + + XFREE(MTYPE_ZVXLAN_SG, vxlan_sg); +} + +static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, + struct in_addr sip, struct in_addr mcast_grp) +{ + zebra_vxlan_sg_t *vxlan_sg; + struct prefix_sg sg; + + sg.family = AF_INET; + sg.prefixlen = IPV4_MAX_BYTELEN; + sg.src = sip; + sg.grp = mcast_grp; + vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg); + if (!vxlan_sg) + return; + + if (vxlan_sg->ref_cnt) + --vxlan_sg->ref_cnt; + + if (!vxlan_sg->ref_cnt) + zebra_vxlan_sg_del(vxlan_sg); +} + +static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, + struct in_addr sip, struct in_addr mcast_grp) +{ + zebra_vxlan_sg_t *vxlan_sg; + struct prefix_sg sg; + + sg.family = AF_INET; + sg.prefixlen = IPV4_MAX_BYTELEN; + sg.src = sip; + sg.grp = mcast_grp; + vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg); + if (vxlan_sg) + ++vxlan_sg->ref_cnt; + + return vxlan_sg; +} + +static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, + struct in_addr mcast_grp) +{ + struct zebra_vrf *zvrf; + + if (!local_vtep_ip.s_addr || !mcast_grp.s_addr) + return; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; + + zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp); +} + +static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, + struct in_addr mcast_grp) +{ + struct zebra_vrf *zvrf; + + if (!local_vtep_ip.s_addr || !mcast_grp.s_addr) + return; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; + zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp); +} + +static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg) +{ + zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data; + + zebra_vxlan_sg_del(vxlan_sg); +} |
