diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 259e6465c4..9e71f1855c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2160,11 +2160,15 @@ static int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) /* Update and advertise the type-3 route (only one) followed by the * locally learnt type-2 routes (MACIP) - for this VNI. + * + * RT-3 only if doing head-end replication */ - build_evpn_type3_prefix(&p, vpn->originator_ip); - ret = update_evpn_route(bgp, vpn, &p, 0, 0); - if (ret) - return ret; + if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) { + build_evpn_type3_prefix(&p, vpn->originator_ip); + ret = update_evpn_route(bgp, vpn, &p, 0, 0); + if (ret) + return ret; + } return update_all_type2_routes(bgp, vpn); } @@ -3388,27 +3392,32 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Locate type-3 route for VNI in the per-VNI table and use its * attributes to create and advertise the type-3 route for this VNI * in the global table. + * + * RT-3 only if doing head-end replication */ - build_evpn_type3_prefix(&p, vpn->originator_ip); - rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); - if (!rn) /* unexpected */ - return 0; - for (pi = rn->info; pi; pi = pi->next) - if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP - && pi->sub_type == BGP_ROUTE_STATIC) - break; - if (!pi) /* unexpected */ - return 0; - attr = pi->attr; + if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) { + build_evpn_type3_prefix(&p, vpn->originator_ip); + rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); + if (!rn) /* unexpected */ + return 0; + for (pi = rn->info; pi; pi = pi->next) + if (pi->peer == bgp->peer_self && + pi->type == ZEBRA_ROUTE_BGP + && pi->sub_type == BGP_ROUTE_STATIC) + break; + if (!pi) /* unexpected */ + return 0; + attr = pi->attr; - global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, - (struct prefix *)&p, &vpn->prd); - update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, &pi, 0, - mac_mobility_seqnum(attr)); + global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)&p, &vpn->prd); + update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, + 1, &pi, 0, mac_mobility_seqnum(attr)); - /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_rn, afi, safi); - bgp_unlock_node(global_rn); + /* Schedule for processing and unlock node. */ + bgp_process(bgp, global_rn, afi, safi); + bgp_unlock_node(global_rn); + } /* Now, walk this VNI's route table and use the route and its attribute * to create and schedule route in global table. @@ -3522,6 +3531,42 @@ static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) delete_withdraw_vni_routes(bgp, vpn); } +/* + * Create RT-3 for a VNI and schedule for processing and advertisement. + * This is invoked upon flooding mode changing to head-end replication. + */ +static void create_advertise_type3(struct hash_backet *backet, void *data) +{ + struct bgpevpn *vpn = backet->data; + struct bgp *bgp = data; + struct prefix_evpn p; + + if (!vpn || !is_vni_live(vpn)) + return; + + build_evpn_type3_prefix(&p, vpn->originator_ip); + if (update_evpn_route(bgp, vpn, &p, 0, 0)) + flog_err(EC_BGP_EVPN_ROUTE_CREATE, + "Type3 route creation failure for VNI %u", vpn->vni); +} + +/* + * Delete RT-3 for a VNI and schedule for processing and withdrawal. + * This is invoked upon flooding mode changing to drop BUM packets. + */ +static void delete_withdraw_type3(struct hash_backet *backet, void *data) +{ + struct bgpevpn *vpn = backet->data; + struct bgp *bgp = data; + struct prefix_evpn p; + + if (!vpn || !is_vni_live(vpn)) + return; + + build_evpn_type3_prefix(&p, vpn->originator_ip); + delete_evpn_route(bgp, vpn, &p); +} + /* * Process received EVPN type-2 route (advertise or withdraw). */ @@ -5481,13 +5526,19 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, /* filter routes as nexthop database has changed */ bgp_filter_evpn_routes_upon_martian_nh_change(bgp); - /* Create EVPN type-3 route and schedule for processing. */ - build_evpn_type3_prefix(&p, vpn->originator_ip); - if (update_evpn_route(bgp, vpn, &p, 0, 0)) { - flog_err(EC_BGP_EVPN_ROUTE_CREATE, - "%u: Type3 route creation failure for VNI %u", - bgp->vrf_id, vni); - return -1; + /* + * Create EVPN type-3 route and schedule for processing. + * + * RT-3 only if doing head-end replication + */ + if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) { + build_evpn_type3_prefix(&p, vpn->originator_ip); + if (update_evpn_route(bgp, vpn, &p, 0, 0)) { + flog_err(EC_BGP_EVPN_ROUTE_CREATE, + "%u: Type3 route creation failure for VNI %u", + bgp->vrf_id, vni); + return -1; + } } /* If we have learnt and retained remote routes (VTEPs, MACs) for this @@ -5585,6 +5636,26 @@ int bgp_evpn_local_es_add(struct bgp *bgp, return 0; } +/* + * Handle change in setting for BUM handling. The supported values + * are head-end replication and dropping all BUM packets. Any change + * should be registered with zebra. Also, if doing head-end replication, + * need to advertise local VNIs as EVPN RT-3 wheras, if BUM packets are + * to be dropped, the RT-3s must be withdrawn. + */ +void bgp_evpn_flood_control_change(struct bgp *bgp) +{ + zlog_info("L2VPN EVPN BUM handling is %s", + bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL ? + "Flooding" : "Flooding Disabled"); + + bgp_zebra_vxlan_flood_control(bgp, bgp->vxlan_flood_ctrl); + if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) + hash_iterate(bgp->vnihash, create_advertise_type3, bgp); + else if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED) + hash_iterate(bgp->vnihash, delete_withdraw_type3, bgp); +} + /* * Cleanup EVPN information on disable - Need to delete and withdraw * EVPN routes from peers. @@ -5652,6 +5723,9 @@ void bgp_evpn_init(struct bgp *bgp) bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm; bgp->l2vnis = list_new(); bgp->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp; + + /* Default BUM handling is to do head-end replication. */ + bgp->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; } void bgp_evpn_vrf_delete(struct bgp *bgp_vrf) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 968d5a0b3f..8728fdcab7 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -145,6 +145,7 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, struct ipaddr *originator_ip); extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi, struct ipaddr *originator_ip); +extern void bgp_evpn_flood_control_change(struct bgp *bgp); extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp); extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 4e38d73146..90c9db3dfe 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2807,6 +2807,40 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) } } +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_evpn_vty_clippy.c" +#endif + +DEFPY(bgp_evpn_flood_control, + bgp_evpn_flood_control_cmd, + "[no$no] flooding ", + NO_STR + "Specify handling for BUM packets\n" + "Do not flood any BUM packets\n" + "Flood BUM packets using head-end replication\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + enum vxlan_flood_control flood_ctrl; + + if (!bgp) + return CMD_WARNING; + + if (disable && !no) + flood_ctrl = VXLAN_FLOOD_DISABLED; + else if (her || no) + flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; + else + return CMD_WARNING; + + if (bgp->vxlan_flood_ctrl == flood_ctrl) + return CMD_SUCCESS; + + bgp->vxlan_flood_ctrl = flood_ctrl; + bgp_evpn_flood_control_change(bgp); + + return CMD_SUCCESS; +} + DEFUN (bgp_evpn_advertise_default_gw_vni, bgp_evpn_advertise_default_gw_vni_cmd, "advertise-default-gw", @@ -3210,6 +3244,12 @@ DEFUN(show_bgp_l2vpn_evpn_vni, json_object_string_add(json, "advertiseAllVnis", is_evpn_enabled() ? "Enabled" : "Disabled"); + json_object_string_add( + json, "flooding", + bgp_def->vxlan_flood_ctrl + == VXLAN_FLOOD_HEAD_END_REPL + ? "Head-end replication" + : "Disabled"); json_object_int_add(json, "numVnis", num_vnis); json_object_int_add(json, "numL2Vnis", num_l2vnis); json_object_int_add(json, "numL3Vnis", num_l3vnis); @@ -3219,6 +3259,11 @@ DEFUN(show_bgp_l2vpn_evpn_vni, : "Disabled"); vty_out(vty, "Advertise All VNI flag: %s\n", is_evpn_enabled() ? "Enabled" : "Disabled"); + vty_out(vty, "BUM flooding: %s\n", + bgp_def->vxlan_flood_ctrl + == VXLAN_FLOOD_HEAD_END_REPL + ? "Head-end replication" + : "Disabled"); vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis); vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis); } @@ -4874,6 +4919,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED) + vty_out(vty, " flooding disable\n"); + if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) { if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name) @@ -4965,6 +5013,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd); /* test commands */ install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e2bdf38350..b2148e52c6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1931,6 +1931,29 @@ int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) return zclient_send_message(zclient); } +int bgp_zebra_vxlan_flood_control(struct bgp *bgp, + enum vxlan_flood_control flood_ctrl) +{ + struct stream *s; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_VXLAN_FLOOD_CONTROL, bgp->vrf_id); + stream_putc(s, flood_ctrl); + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise) { struct stream *s; @@ -1948,6 +1971,10 @@ int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise) zclient_create_header(s, ZEBRA_ADVERTISE_ALL_VNI, bgp->vrf_id); stream_putc(s, advertise); + /* Also inform current BUM handling setting. This is really + * relevant only when 'advertise' is set. + */ + stream_putc(s, bgp->vxlan_flood_ctrl); stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 1118eaab24..458730dd43 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -72,6 +72,8 @@ extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni); extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t); extern int bgp_zebra_advertise_all_vni(struct bgp *, int); +extern int bgp_zebra_vxlan_flood_control(struct bgp *bgp, + enum vxlan_flood_control flood_ctrl); extern int bgp_zebra_num_connects(void); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 861435c036..cef5394b09 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -485,6 +485,11 @@ struct bgp { /* EVPN - use RFC 8365 to auto-derive RT */ int advertise_autort_rfc8365; + /* + * Flooding mechanism for BUM packets for VxLAN-EVPN. + */ + enum vxlan_flood_control vxlan_flood_ctrl; + /* Hash table of Import RTs to EVIs */ struct hash *import_rt_hash; diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 4291388567..83f55939ce 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -208,6 +208,8 @@ bgpd_bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS) bgpd_bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic bgpd_bgpd_rpki_la_LIBADD = $(RTRLIB_LIBS) +bgpd/bgp_evpn_vty_clippy.c: $(CLIPPY_DEPS) +bgpd/bgp_evpn_vty.$(OBJEXT): bgpd/bgp_evpn_vty_clippy.c bgpd/bgp_vty_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_vty.$(OBJEXT): bgpd/bgp_vty_clippy.c bgpd/bgp_route_clippy.c: $(CLIPPY_DEPS) diff --git a/lib/log.c b/lib/log.c index 2d800baae1..10cb2cd8a4 100644 --- a/lib/log.c +++ b/lib/log.c @@ -980,6 +980,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_IPSET_DESTROY), DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD), DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE), + DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL), }; #undef DESC_ENTRY diff --git a/lib/vxlan.h b/lib/vxlan.h index ba3dbb05c8..bcf8354539 100644 --- a/lib/vxlan.h +++ b/lib/vxlan.h @@ -26,4 +26,13 @@ typedef uint32_t vni_t; #define VNI_MAX 16777215 /* (2^24 - 1) */ +/* Flooding mechanisms for BUM packets. */ +/* Currently supported mechanisms are head-end (ingress) replication + * (which is the default) and no flooding. Future options could be + * using PIM-SM, PIM-Bidir etc. + */ +enum vxlan_flood_control { + VXLAN_FLOOD_HEAD_END_REPL = 0, + VXLAN_FLOOD_DISABLED, +}; #endif /* __VXLAN_H__ */ diff --git a/lib/zclient.h b/lib/zclient.h index 54f3635901..97ebb0811c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -155,6 +155,7 @@ typedef enum { ZEBRA_IPTABLE_ADD, ZEBRA_IPTABLE_DELETE, ZEBRA_IPTABLE_NOTIFY_OWNER, + ZEBRA_VXLAN_FLOOD_CONTROL, } zebra_message_types_t; struct redist_proto { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index c193a0c47a..149d2cb6a5 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2439,6 +2439,7 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_IPSET_ENTRY_DELETE] = zread_ipset_entry, [ZEBRA_IPTABLE_ADD] = zread_iptable, [ZEBRA_IPTABLE_DELETE] = zread_iptable, + [ZEBRA_VXLAN_FLOOD_CONTROL] = zebra_vxlan_flood_control, }; #if defined(HANDLE_ZAPI_FUZZING) diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 78f6331d03..a39d74b08b 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -22,6 +22,8 @@ #if !defined(__ZEBRA_VRF_H__) #define __ZEBRA_VRF_H__ +#include "vxlan.h" + #include #include #include @@ -123,6 +125,11 @@ struct zebra_vrf { /* l3-vni info */ vni_t l3vni; + /* + * Flooding mechanism for BUM packets for VxLAN-EVPN. + */ + enum vxlan_flood_control vxlan_flood_ctrl; + /* Route Installs */ uint64_t installs; uint64_t removals; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index f8417503ef..5078eff590 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3097,7 +3097,9 @@ 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) { - return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); + if (is_vxlan_flooding_head_end()) + return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); + return 0; } /* @@ -3114,6 +3116,28 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) return kernel_del_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); } +/* + * Install or uninstall flood entries in the kernel corresponding to + * remote VTEPs. This is invoked upon change to BUM handling. + */ +static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, + void *zvrf) +{ + zebra_vni_t *zvni; + zebra_vtep_t *zvtep; + + zvni = (zebra_vni_t *)backet->data; + if (!zvni) + return; + + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { + if (is_vxlan_flooding_head_end()) + zvni_vtep_install(zvni, &zvtep->vtep_ip); + else + zvni_vtep_uninstall(zvni, &zvtep->vtep_ip); + } +} + /* * Cleanup VNI/VTEP and update kernel */ @@ -6897,6 +6921,46 @@ int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) return 0; } +/* + * Handle message from client to specify the flooding mechanism for + * BUM packets. The default is to do head-end (ingress) replication + * and the other supported option is to disable it. This applies to + * all BUM traffic and disabling it applies to both the transmit and + * receive direction. + */ +void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + enum vxlan_flood_control flood_ctrl; + + if (zvrf_id(zvrf) != VRF_DEFAULT) { + zlog_err("EVPN flood control for non-default VRF %u", + zvrf_id(zvrf)); + return; + } + + s = msg; + STREAM_GETC(s, flood_ctrl); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("EVPN flood control %u, currently %u", + flood_ctrl, zvrf->vxlan_flood_ctrl); + + if (zvrf->vxlan_flood_ctrl == flood_ctrl) + return; + + zvrf->vxlan_flood_ctrl = flood_ctrl; + + /* Install or uninstall flood entries corresponding to + * remote VTEPs. + */ + hash_iterate(zvrf->vni_table, zvni_handle_flooding_remote_vteps, + zvrf); + +stream_failure: + return; +} + /* * Handle message from client to enable/disable advertisement of g/w macip * routes @@ -7073,12 +7137,15 @@ stream_failure: * When enabled, the VNI hash table will be built and MAC FDB table read; * when disabled, the entries should be deleted and remote VTEPs and MACs * uninstalled from the kernel. + * This also informs the setting for BUM handling at the time this change + * occurs; it is relevant only when specifying "learn". */ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS) { struct stream *s = NULL; int advertise = 0; struct zebra_ns *zns = NULL; + enum vxlan_flood_control flood_ctrl; if (zvrf_id(zvrf) != VRF_DEFAULT) { zlog_debug("EVPN VNI Adv for non-default VRF %u", @@ -7088,17 +7155,22 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS) s = msg; STREAM_GETC(s, advertise); + STREAM_GETC(s, flood_ctrl); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("EVPN VNI Adv %s, currently %s", + zlog_debug("EVPN VNI Adv %s, currently %s, flood control %u", advertise ? "enabled" : "disabled", - is_evpn_enabled() ? "enabled" : "disabled"); + is_evpn_enabled() ? "enabled" : "disabled", + flood_ctrl); if (zvrf->advertise_all_vni == advertise) return; zvrf->advertise_all_vni = advertise; if (is_evpn_enabled()) { + /* Note BUM handling */ + zvrf->vxlan_flood_ctrl = flood_ctrl; + /* Build VNI hash table and inform BGP. */ zvni_build_hash_table(); diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index a6c668785f..f03cd3d541 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -44,6 +44,15 @@ static inline int is_evpn_enabled() return zvrf ? zvrf->advertise_all_vni : 0; } +static inline int +is_vxlan_flooding_head_end() +{ + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); + + if (!zvrf) + return 0; + return (zvrf->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL); +} /* VxLAN interface change flags of interest. */ #define ZEBRA_VXLIF_LOCAL_IP_CHANGE 0x1 @@ -57,6 +66,7 @@ extern void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS);