bgpd: Add '[no] flood <disable|head-end-replication>'

Add the '[no] flood <disable|head-end-replication>' command
to the l2vpn evpn afi/safi sub commands for bgp.  This command
when entered as 'flood disable' will turn off type 3 route
generation for the transmittal of the type 3 route necessary
for BUM replication on the remote VTEP.  Additionally it will
turn off the BUM handling via the new zebra command,
ZEBRA_VXLAN_FLOOD_CONTROL.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2018-10-04 19:20:12 -04:00
parent fbac9605a7
commit fd06964433
7 changed files with 186 additions and 30 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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 <disable$disable|head-end-replication$her>",
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);

View File

@ -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;
@ -1951,7 +1974,7 @@ int bgp_zebra_advertise_all_vni(struct bgp *bgp, int 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_putc(s, bgp->vxlan_flood_ctrl);
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);

View File

@ -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);

View File

@ -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;

View File

@ -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)