diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e2bdf38350..214d7e4d9c 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1948,6 +1948,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, VXLAN_FLOOD_HEAD_END_REPL); stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); 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);