bgpd: support for Ethernet Segments and Type-1/EAD routes

This is the base patch that brings in support for Type-1 routes.
It includes support for -
- Ethernet Segment (ES) management
- EAD route handling
- MAC-IP (Type-2) routes with a non-zero ESI i.e. Aliasing for
  active-active multihoming
- Initial infra for consistency checking. Consistency checking
  is a fundamental feature for active-active solutions like MLAG.
  We will try to levarage the info in the EAD-ES/EAD-EVI routes to
  detect inconsitencies in access config across VTEPs attached to
  the same Ethernet Segment.

Functionality Overview -
========================
1. Ethernet segments are created in zebra and associated with
access VLANs. zebra sends that info as ES and ES-EVI objects to BGP.
2. BGP advertises EAD-ES and EAD-EVI routes for the locally attached
ethernet segments.
3. Similarly BGP processes EAD-ES and EAD-EVI routes from peers
and translates them into ES-VTEP objects which are then sent to zebra
as remote ESs.
4. Each ES in zebra is associated with a list of active VTEPs which
is then translated into a L2-NHG (nexthop group). This is the ES
"Alias" entry
5. MAC-IP routes with a non-zero ESI use the alias entry created in
(4.) to forward traffic i.e. a MAC-ECMP is done to these remote-ES
destinations.

EAD route management (route table and key) -
============================================
1. Local EAD-ES routes
a. route-table: per-ES route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
b. route-table: per-VNI route-table
Not added
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)

2. Remote EAD-ES routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=ES-RD, ESI, ET=0xffffffff, VTEP-IP)
c. route-table: global route-table
key: {RD=ES-RD, ESI, ET=0xffffffff)

3. Local EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)

4. Remote EAD-EVI routes
a. route-table: per-ES route-table
Not added
b. route-table: per-VNI route-table
key: {RD=0, ESI, ET=0, VTEP-IP)
c. route-table: global route-table
key: {RD=L2-VNI-RD, ESI, ET=0)

Please refer to bgp_evpn_mh.h for info on how the data-structures are
organized.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2020-03-27 14:43:50 -07:00
parent 0a50c24813
commit c44ab6f1f3
11 changed files with 3221 additions and 851 deletions

View file

@ -55,10 +55,8 @@
/*
* Definitions and external declarations.
*/
extern struct zclient *zclient;
DEFINE_QOBJ_TYPE(bgpevpn)
DEFINE_QOBJ_TYPE(evpnes)
DEFINE_QOBJ_TYPE(bgp_evpn_es)
/*
@ -94,7 +92,7 @@ static bool vni_hash_cmp(const void *p1, const void *p2)
return (vpn1->vni == vpn2->vni);
}
static int vni_list_cmp(void *p1, void *p2)
int vni_list_cmp(void *p1, void *p2)
{
const struct bgpevpn *vpn1 = p1;
const struct bgpevpn *vpn2 = p2;
@ -540,19 +538,54 @@ static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
}
struct bgp_node *bgp_global_evpn_node_get(
struct bgp_table *table, afi_t afi,
safi_t safi, const struct prefix_evpn *evp,
struct prefix_rd *prd)
{
struct prefix_evpn global_p;
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
/* prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy of the prefix
*/
evpn_type1_prefix_global_copy(&global_p, evp);
evp = &global_p;
}
return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd);
}
struct bgp_node *bgp_global_evpn_node_lookup(
struct bgp_table *table, afi_t afi,
safi_t safi, const struct prefix_evpn *evp,
struct prefix_rd *prd)
{
struct prefix_evpn global_p;
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
/* prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy of the prefix
*/
evpn_type1_prefix_global_copy(&global_p, evp);
evp = &global_p;
}
return bgp_afi_node_lookup(table, afi, safi, (struct prefix *)evp, prd);
}
/*
* Add (update) or delete MACIP from zebra.
*/
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p,
struct in_addr remote_vtep_ip, int add,
uint8_t flags, uint32_t seq)
uint8_t flags, uint32_t seq, esi_t *esi)
{
struct stream *s;
int ipa_len;
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
char buf3[INET6_ADDRSTRLEN];
static struct in_addr zero_remote_vtep_ip;
/* Check socket. */
if (!zclient || zclient->sock < 0)
@ -566,6 +599,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
__func__);
return 0;
}
if (!esi)
esi = zero_esi;
s = zclient->obuf;
stream_reset(s);
@ -583,13 +619,20 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
stream_putl(s, ipa_len);
stream_put(s, &p->prefix.macip_addr.ip.ip.addr, ipa_len);
}
stream_put_in_addr(s, &remote_vtep_ip);
/* tape out the VTEP-IP if the ESI is non-zero to avoid incorrect
* mods
*/
if (memcmp(zero_esi, esi, sizeof(esi_t)))
stream_put_in_addr(s, &remote_vtep_ip);
else
stream_put_in_addr(s, &zero_remote_vtep_ip);
/* TX flags - MAC sticky status and/or gateway mac */
/* Also TX the sequence number of the best route. */
if (add) {
stream_putc(s, flags);
stream_putl(s, seq);
stream_put(s, esi, sizeof(esi_t));
}
stream_putw_at(s, 0, stream_get_endp(s));
@ -873,7 +916,10 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
ret = bgp_zebra_send_remote_macip(
bgp, vpn, p, pi->attr->nexthop, 1, flags,
mac_mobility_seqnum(pi->attr));
mac_mobility_seqnum(pi->attr),
bgp_evpn_attr_get_esi(pi->attr));
} else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) {
ret = bgp_evpn_remote_es_evi_add(bgp, vpn, p);
} else {
switch (pi->attr->pmsi_tnl_type) {
case PMSI_TNLTYPE_INGR_REPL:
@ -903,7 +949,9 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
0, 0, 0);
0, 0, 0, NULL);
else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p);
else
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p,
VXLAN_FLOOD_DISABLED, 0);
@ -929,8 +977,9 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table is a 2-level tree (RD-level + Prefix-level) similar to
* L3VPN routes.
*/
global_dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
bgp_dest_get_prefix(dest), &vpn->prd);
global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)bgp_dest_get_prefix(dest),
&vpn->prd);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@ -950,8 +999,9 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Calculate the best path for an EVPN route. Install/update best path in zebra,
* if appropriate.
* Note: vpn is NULL for local EAD-ES routes.
*/
static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_dest *dest)
{
struct bgp_path_info *old_select, *new_select;
@ -1023,7 +1073,8 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
*/
if (old_select && old_select->peer == bgp->peer_self
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_STATIC)
&& old_select->sub_type == BGP_ROUTE_STATIC
&& vpn)
evpn_delete_old_local_route(bgp, vpn, dest, old_select);
} else {
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
@ -1235,8 +1286,9 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
/* get the route node in global table */
dest = bgp_afi_node_get(bgp_evpn->rib[afi][safi], afi, safi,
(struct prefix *)evp, &bgp_vrf->vrf_prd);
dest = bgp_global_evpn_node_get(bgp_evpn->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)evp,
&bgp_vrf->vrf_prd);
assert(dest);
/* create or update the route entry within the route node */
@ -1450,7 +1502,7 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
*/
static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p, uint8_t flags,
uint32_t seq)
uint32_t seq, esi_t *esi)
{
struct bgp_dest *dest;
struct attr attr;
@ -1472,7 +1524,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
attr.router_flag = CHECK_FLAG(flags,
ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0;
if (esi)
memcpy(&attr.esi, esi, sizeof(esi_t));
/* PMSI is only needed for type-3 routes */
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
@ -1562,8 +1615,9 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
if (route_change) {
struct bgp_path_info *global_pi;
dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)p, &vpn->prd);
dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)p,
&vpn->prd);
update_evpn_route_entry(bgp, vpn, afi, safi, dest, attr_new, 1,
&global_pi, flags, seq);
@ -1619,8 +1673,8 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp)
return 0;
/* locate the global route entry for this type-5 prefix */
dest = bgp_afi_node_lookup(bgp_evpn->rib[afi][safi], afi, safi,
(struct prefix *)evp, &bgp_vrf->vrf_prd);
dest = bgp_global_evpn_node_lookup(bgp_evpn->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)evp, &bgp_vrf->vrf_prd);
if (!dest)
return 0;
@ -1656,8 +1710,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table is a 2-level tree (RD-level + Prefix-level) similar to
* L3VPN routes.
*/
global_dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
(struct prefix *)p, &vpn->prd);
global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)p, &vpn->prd);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@ -1800,9 +1854,9 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
bgp_path_info_unlock(pi);
/* Update route in global routing table. */
rd_dest = bgp_afi_node_get(bgp->rib[afi][safi], afi,
safi, (struct prefix *)evp,
&vpn->prd);
rd_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi,
safi, (const struct prefix_evpn *)evp,
&vpn->prd);
assert(rd_dest);
update_evpn_route_entry(bgp, vpn, afi, safi, rd_dest,
attr_new, 0, &global_pi, 0,
@ -1958,7 +2012,7 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
== VXLAN_FLOOD_HEAD_END_REPL) {
build_evpn_type3_prefix(&p, vpn->originator_ip);
ret = update_evpn_route(bgp, vpn, &p, 0, 0);
ret = update_evpn_route(bgp, vpn, &p, 0, 0, NULL);
if (ret)
return ret;
}
@ -2202,6 +2256,14 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_path_info *pi;
struct attr *attr_new;
int ret;
struct prefix_evpn ad_evp;
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
p = evpn_type1_prefix_vni_copy(&ad_evp, p,
parent_pi->attr->nexthop);
/* Create (or fetch) route within the VNI. */
/* NOTE: There is no RD here. */
@ -2336,6 +2398,14 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_dest *dest;
struct bgp_path_info *pi;
int ret;
struct prefix_evpn ad_evp;
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
p = evpn_type1_prefix_vni_copy(&ad_evp, p,
parent_pi->attr->nexthop);
/* Locate route within the VNI. */
/* NOTE: There is no RD here. */
@ -2727,6 +2797,11 @@ static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
if (ret)
return ret;
ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
1);
if (ret)
return ret;
return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE,
1);
}
@ -2755,6 +2830,12 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
if (ret)
return ret;
ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
1);
if (ret)
return ret;
return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE,
0);
}
@ -2853,6 +2934,7 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
struct attr *attr = pi->attr;
struct ecommunity *ecom;
int i;
struct prefix_evpn ad_evp;
assert(attr);
@ -2860,6 +2942,7 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|| evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
|| evp->prefix.route_type == BGP_EVPN_ES_ROUTE
|| evp->prefix.route_type == BGP_EVPN_AD_ROUTE
|| evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
return 0;
@ -2867,6 +2950,12 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0;
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
evp = evpn_type1_prefix_vni_copy(&ad_evp, evp, attr->nexthop);
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return -1;
@ -2880,7 +2969,7 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
struct ecommunity_val eval_tmp;
struct irt_node *irt; /* import rt for l2vni */
struct vrf_irt_node *vrf_irt; /* import rt for l3vni */
struct evpnes *es;
struct bgp_evpn_es *es;
/* Only deal with RTs */
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
@ -2898,6 +2987,7 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
*/
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
evp->prefix.route_type == BGP_EVPN_IMET_ROUTE ||
evp->prefix.route_type == BGP_EVPN_AD_ROUTE ||
evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
irt = lookup_import_rt(bgp, eval);
@ -2945,9 +3035,9 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
/* we will match based on the entire esi to avoid
* imoort of an es route for esi2 into esi1
*/
es = bgp_evpn_lookup_es(bgp, &evp->prefix.es_addr.esi);
es = bgp_evpn_es_find(&evp->prefix.es_addr.esi);
if (es && is_es_local(es))
install_uninstall_route_in_es(
bgp_evpn_es_route_install_uninstall(
bgp, es, afi, safi, evp, pi, import);
}
}
@ -3081,8 +3171,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
return 0;
attr = pi->attr;
global_dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)&p, &vpn->prd);
global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)&p, &vpn->prd);
update_evpn_route_entry(bgp, vpn, afi, safi, global_dest, attr,
1, &pi, 0, mac_mobility_seqnum(attr));
@ -3115,8 +3205,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
* attribute.
*/
attr = pi->attr;
global_dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)evp, &vpn->prd);
global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)evp, &vpn->prd);
assert(global_dest);
update_evpn_route_entry(bgp, vpn, afi, safi, global_dest, attr,
1, &global_pi, 0,
@ -3152,8 +3242,8 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
/* Remove type-3 route for this VNI from global table. */
build_evpn_type3_prefix(&p, vpn->originator_ip);
global_dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
(struct prefix *)&p, &vpn->prd);
global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
(const struct prefix_evpn *)&p, &vpn->prd);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@ -3220,7 +3310,7 @@ static void create_advertise_type3(struct hash_bucket *bucket, void *data)
return;
build_evpn_type3_prefix(&p, vpn->originator_ip);
if (update_evpn_route(bgp, vpn, &p, 0, 0))
if (update_evpn_route(bgp, vpn, &p, 0, 0, NULL))
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
"Type3 route creation failure for VNI %u", vpn->vni);
}
@ -3288,8 +3378,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
/* Copy Ethernet Seg Identifier */
memcpy(&evpn.eth_s_id.val, pfx, ESI_LEN);
pfx += ESI_LEN;
if (attr)
memcpy(&attr->esi, pfx, sizeof(esi_t));
pfx += sizeof(esi_t);
/* Copy Ethernet Tag */
memcpy(&eth_tag, pfx, 4);
@ -3486,8 +3577,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
memset(&evpn, 0, sizeof(evpn));
/* Fetch ESI */
memcpy(&evpn.eth_s_id.val, pfx, 10);
pfx += 10;
if (attr)
memcpy(&attr->esi, pfx, sizeof(esi_t));
pfx += ESI_BYTES;
/* Fetch Ethernet Tag. */
memcpy(&eth_tag, pfx, 4);
@ -3583,9 +3675,9 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8);
if (attr)
stream_put(s, &(attr->evpn_overlay.eth_s_id), 10);
stream_put(s, &attr->esi, sizeof(esi_t));
else
stream_put(s, &temp, 10);
stream_put(s, 0, sizeof(esi_t));
stream_putl(s, p_evpn_p->prefix_addr.eth_tag);
stream_putc(s, p_evpn_p->prefix_addr.ip_prefix_length);
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
@ -4288,6 +4380,15 @@ char *bgp_evpn_route2str(const struct prefix_evpn *p, char *buf, int len)
is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN,
inet_ntoa(p->prefix.es_addr.ip.ipaddr_v4));
} else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) {
snprintf(buf, len, "[%d]:[%u]:[%s]:[%d]:[%s]",
p->prefix.route_type,
p->prefix.ead_addr.eth_tag,
esi_to_str(&p->prefix.ead_addr.esi,
buf3, sizeof(buf3)),
is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN,
inet_ntoa(p->prefix.ead_addr.ip.ipaddr_v4));
} else {
/* For EVPN route types not supported yet. */
snprintf(buf, len, "(unsupported route type %d)",
@ -4327,7 +4428,7 @@ void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
stream_putc(s, len);
stream_put(s, prd->val, 8); /* RD */
if (attr)
stream_put(s, &attr->evpn_overlay.eth_s_id, ESI_LEN);
stream_put(s, &attr->esi, ESI_BYTES);
else
stream_put(s, 0, 10);
stream_putl(s, evp->prefix.macip_addr.eth_tag); /* Ethernet Tag ID */
@ -4362,6 +4463,16 @@ void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
stream_put_in_addr(s, &evp->prefix.es_addr.ip.ipaddr_v4);
break;
case BGP_EVPN_AD_ROUTE:
/* RD, ESI, EthTag, 1 VNI */
len = RD_BYTES + ESI_BYTES + EVPN_ETH_TAG_BYTES + BGP_LABEL_BYTES;
stream_putc(s, len);
stream_put(s, prd->val, RD_BYTES); /* RD */
stream_put(s, evp->prefix.ead_addr.esi.val, ESI_BYTES); /* ESI */
stream_putl(s, evp->prefix.ead_addr.eth_tag); /* Ethernet Tag */
stream_put(s, label, BGP_LABEL_BYTES);
break;
case BGP_EVPN_IP_PREFIX_ROUTE:
/* TODO: AddPath support. */
evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr);
@ -4449,7 +4560,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
break;
case BGP_EVPN_ES_ROUTE:
if (process_type4_route(peer, afi, safi,
if (bgp_evpn_type4_route_process(peer, afi, safi,
withdraw ? NULL : attr, pnt,
psize, addpath_id)) {
flog_err(
@ -4460,6 +4571,18 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
}
break;
case BGP_EVPN_AD_ROUTE:
if (bgp_evpn_type1_route_process(peer, afi, safi,
withdraw ? NULL : attr, pnt,
psize, addpath_id)) {
flog_err(
EC_BGP_PKT_PROCESS,
"%u:%s - Error in processing EVPN type-1 NLRI size %d",
peer->bgp->vrf_id, peer->host, psize);
return BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE;
}
break;
case BGP_EVPN_IP_PREFIX_ROUTE:
if (process_type5_route(peer, afi, safi,
withdraw ? NULL : attr, pnt,
@ -4638,7 +4761,7 @@ void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
*/
void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn)
{
char buf[100];
char buf[BGP_EVPN_PREFIX_RD_LEN];
vpn->prd.family = AF_UNSPEC;
vpn->prd.prefixlen = 64;
@ -4722,6 +4845,8 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
/* add to l2vni list on corresponding vrf */
bgpevpn_link_to_l3vni(vpn);
bgp_evpn_vni_es_init(vpn);
QOBJ_REG(vpn, bgpevpn);
return vpn;
}
@ -4734,6 +4859,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
*/
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
{
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
bgp_table_unlock(vpn->route_table);
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
@ -4866,7 +4992,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
* Handle add of a local MACIP.
*/
int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
struct ipaddr *ip, uint8_t flags, uint32_t seq)
struct ipaddr *ip, uint8_t flags, uint32_t seq, esi_t *esi)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
@ -4882,7 +5008,7 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
/* Create EVPN type-2 route and schedule for processing. */
build_evpn_type2_prefix(&p, mac, ip);
if (update_evpn_route(bgp, vpn, &p, flags, seq)) {
if (update_evpn_route(bgp, vpn, &p, flags, seq, esi)) {
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
@ -5254,7 +5380,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
== VXLAN_FLOOD_HEAD_END_REPL) {
build_evpn_type3_prefix(&p, vpn->originator_ip);
if (update_evpn_route(bgp, vpn, &p, 0, 0)) {
if (update_evpn_route(bgp, vpn, &p, 0, 0, NULL)) {
flog_err(EC_BGP_EVPN_ROUTE_CREATE,
"%u: Type3 route creation failure for VNI %u",
bgp->vrf_id, vni);
@ -5327,9 +5453,6 @@ void bgp_evpn_cleanup(struct bgp *bgp)
hash_free(bgp->vnihash);
bgp->vnihash = NULL;
if (bgp->esihash)
hash_free(bgp->esihash);
bgp->esihash = NULL;
list_delete(&bgp->vrf_import_rtl);
list_delete(&bgp->vrf_export_rtl);
@ -5346,9 +5469,6 @@ void bgp_evpn_init(struct bgp *bgp)
{
bgp->vnihash =
hash_create(vni_hash_key_make, vni_hash_cmp, "BGP VNI Hash");
bgp->esihash =
hash_create(esi_hash_keymake, esi_cmp,
"BGP EVPN Local ESI Hash");
bgp->import_rt_hash =
hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
"BGP Import RT Hash");

View file

@ -176,7 +176,7 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
int state);
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
uint8_t flags, uint32_t seq);
uint8_t flags, uint32_t seq, esi_t *esi);
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct ethaddr *rmac,
struct ethaddr *vrr_rmac,

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/* EVPN header for multihoming procedures
*
* Copyright (C) 2019 Cumulus Networks
* Anuradha Karuppiah
*
* This file is part of FRRouting.
*
@ -24,17 +25,236 @@
#include "bgp_evpn.h"
#include "bgp_evpn_private.h"
extern unsigned int esi_hash_keymake(const void *p);
extern bool esi_cmp(const void *p1, const void *p2);
extern int install_uninstall_route_in_es(struct bgp *bgp, struct evpnes *es,
afi_t afi, safi_t safi,
struct prefix_evpn *evp,
struct bgp_path_info *pi, int install);
int process_type4_route(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id);
#define BGP_EVPN_AD_ES_ETH_TAG 0xffffffff
#define BGP_EVPN_AD_EVI_ETH_TAG 0
#define BGP_EVPNES_INCONS_STR_SZ 80
#define BGP_EVPN_FLAG_STR_SZ 5
#define BGP_EVPN_VTEPS_FLAG_STR_SZ (BGP_EVPN_FLAG_STR_SZ * ES_VTEP_MAX_CNT)
#define BGP_EVPN_CONS_CHECK_INTERVAL 60
/* Ethernet Segment entry -
* - Local and remote ESs are maintained in a global RB tree,
* bgp_mh_info->es_rb_tree using ESI as key
* - Local ESs are received from zebra (BGP_EVPNES_LOCAL)
* - Remotes ESs are implicitly created (by reference) by a remote ES-EVI
* (BGP_EVPNES_REMOTE)
* - An ES can be simulatenously LOCAL and REMOTE; infact all LOCAL ESs are
* expected to have REMOTE ES peers.
*/
struct bgp_evpn_es {
/* Ethernet Segment Identifier */
esi_t esi;
char esi_str[ESI_STR_LEN];
/* es flags */
uint32_t flags;
/* created via zebra config */
#define BGP_EVPNES_LOCAL (1 << 0)
/* created implicitly by a remote ES-EVI reference */
#define BGP_EVPNES_REMOTE (1 << 1)
/* local ES link is oper-up */
#define BGP_EVPNES_OPER_UP (1 << 2)
/* enable generation of EAD-EVI routes */
#define BGP_EVPNES_ADV_EVI (1 << 3)
/* consistency checks pending */
#define BGP_EVPNES_CONS_CHECK_PEND (1 << 4)
/* memory used for adding the es to bgp->es_rb_tree */
RB_ENTRY(bgp_evpn_es) rb_node;
/* [EVPNES_LOCAL] memory used for linking the es to
* bgp_mh_info->local_es_list
*/
struct listnode es_listnode;
/* memory used for linking the es to "processing" pending list
* bgp_mh_info->pend_es_list
*/
struct listnode pend_es_listnode;
/* [EVPNES_LOCAL] Id for deriving the RD automatically for this ESI */
uint16_t rd_id;
/* [EVPNES_LOCAL] RD for this ES */
struct prefix_rd prd;
/* [EVPNES_LOCAL] originator ip address */
struct in_addr originator_ip;
/* [EVPNES_LOCAL] Route table for EVPN routes for this ESI-
* - Type-4 local and remote routes
* - Type-1 local routes
*/
struct bgp_table *route_table;
/* list of PEs (bgp_evpn_es_vtep) attached to the ES */
struct list *es_vtep_list;
/* List of ES-EVIs associated with this ES */
struct list *es_evi_list;
/* Number of remote VNIs referencing this ES */
uint32_t remote_es_evi_cnt;
uint32_t inconsistencies;
/* there are one or more EVIs whose VTEP list doesn't match
* with the ES's VTEP list
*/
#define BGP_EVPNES_INCONS_VTEP_LIST (1 << 0)
/* number of es-evi entries whose VTEP list doesn't match
* with the ES's
*/
uint32_t incons_evi_vtep_cnt;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgp_evpn_es)
RB_HEAD(bgp_es_rb_head, bgp_evpn_es);
RB_PROTOTYPE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
/* PE attached to an ES */
struct bgp_evpn_es_vtep {
struct bgp_evpn_es *es; /* parent ES */
struct in_addr vtep_ip;
uint32_t flags;
/* Rxed a Type4 route from this PE */
#define BGP_EVPNES_VTEP_ESR (1 << 0)
/* Active (rxed EAD-ES and EAD-EVI) and can be included as
* a nexthop
*/
#define BGP_EVPNES_VTEP_ACTIVE (1 << 1)
uint32_t evi_cnt; /* es_evis referencing this vtep as an active path */
/* memory used for adding the entry to es->es_vtep_list */
struct listnode es_listnode;
};
/* ES per-EVI info
* - ES-EVIs are maintained per-L2-VNI (vpn->es_evi_rb_tree)
* - ES-EVIs are also linked to the parent ES (es->es_evi_list)
* - Local ES-EVIs are created by zebra (via config). They are linked to a
* per-VNI list (vpn->local_es_evi_list) for quick access
* - Remote ES-EVIs are created implicitly when a bgp_evpn_es_evi_vtep
* references it.
*/
struct bgp_evpn_es_evi {
struct bgp_evpn_es *es;
struct bgpevpn *vpn;
/* ES-EVI flags */
uint32_t flags;
/* local ES-EVI, created by zebra */
#define BGP_EVPNES_EVI_LOCAL (1 << 0)
/* created via a remote VTEP imported by BGP */
#define BGP_EVPNES_EVI_REMOTE (1 << 1)
#define BGP_EVPNES_EVI_INCONS_VTEP_LIST (1 << 2)
/* memory used for adding the es_evi to es_evi->vpn->es_evi_rb_tree */
RB_ENTRY(bgp_evpn_es_evi) rb_node;
/* memory used for linking the es_evi to
* es_evi->vpn->local_es_evi_list
*/
struct listnode l2vni_listnode;
/* memory used for linking the es_evi to
* es_evi->es->es_evi_list
*/
struct listnode es_listnode;
/* list of PEs (bgp_evpn_es_evi_vtep) attached to the ES for this VNI */
struct list *es_evi_vtep_list;
};
/* PE attached to an ES for a VNI. This entry is created when an EAD-per-ES
* or EAD-per-EVI Type1 route is imported into the VNI.
*/
struct bgp_evpn_es_evi_vtep {
struct bgp_evpn_es_evi *es_evi; /* parent ES-EVI */
struct in_addr vtep_ip;
uint32_t flags;
/* Rxed an EAD-per-ES route from the PE */
#define BGP_EVPN_EVI_VTEP_EAD_PER_ES (1 << 0) /* rxed EAD-per-ES */
/* Rxed an EAD-per-EVI route from the PE */
#define BGP_EVPN_EVI_VTEP_EAD_PER_EVI (1 << 1) /* rxed EAD-per-EVI */
/* VTEP is active i.e. will result in the creation of an es-vtep */
#define BGP_EVPN_EVI_VTEP_ACTIVE (1 << 2)
#define BGP_EVPN_EVI_VTEP_EAD (BGP_EVPN_EVI_VTEP_EAD_PER_ES |\
BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
/* memory used for adding the entry to es_evi->es_evi_vtep_list */
struct listnode es_evi_listnode;
struct bgp_evpn_es_vtep *es_vtep;
};
/* multihoming information stored in bgp_master */
#define bgp_mh_info (bm->mh_info)
struct bgp_evpn_mh_info {
/* RB tree of Ethernet segments (used for EVPN-MH) */
struct bgp_es_rb_head es_rb_tree;
/* List of local ESs */
struct list *local_es_list;
/* List of ESs with pending/periodic processing */
struct list *pend_es_list;
/* periodic timer for running background consistency checks */
struct thread *t_cons_check;
/* config knobs for optimizing or interop */
/* Generate EAD-EVI routes even if the ES is oper-down. This can be
* enabled as an optimization to avoid a storm of updates when an ES
* link flaps.
*/
bool ead_evi_adv_for_down_links;
/* Enable ES consistency checking */
bool consistency_checking;
};
/****************************************************************************/
static inline int is_es_local(struct bgp_evpn_es *es)
{
return CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) ? 1 : 0;
}
extern esi_t *zero_esi;
static inline esi_t *bgp_evpn_attr_get_esi(struct attr *attr)
{
return (attr) ? &attr->esi : zero_esi;
}
/****************************************************************************/
extern int bgp_evpn_es_route_install_uninstall(struct bgp *bgp,
struct bgp_evpn_es *es, afi_t afi, safi_t safi,
struct prefix_evpn *evp, struct bgp_path_info *pi,
int install);
int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id);
int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id);
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);
struct in_addr originator_ip, bool oper_up);
extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi);
extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni);
extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni);
extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern void bgp_evpn_mh_init(void);
extern void bgp_evpn_mh_finish(void);
void bgp_evpn_vni_es_init(struct bgpevpn *vpn);
void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn);
void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj);
void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail);
void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
bool uj, bool detail);
void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail);
struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi);
#endif /* _FRR_BGP_EVPN_MH_H */

View file

@ -34,6 +34,20 @@
* in bits */
#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
/* EVPN route RD buffer length */
#define BGP_EVPN_PREFIX_RD_LEN 100
/* packet sizes for EVPN routes */
/* Type-1 route should be 25 bytes
* RD (8), ESI (10), eth-tag (4), vni (3)
*/
#define BGP_EVPN_TYPE1_PSIZE 25
/* Type-4 route should be either 23 or 35 bytes
* RD (8), ESI (10), ip-len (1), ip (4 or 16)
*/
#define BGP_EVPN_TYPE4_V4_PSIZE 23
#define BGP_EVPN_TYPE4_V6_PSIZE 34
/* EVPN route types. */
typedef enum {
BGP_EVPN_AD_ROUTE = 1, /* Ethernet Auto-Discovery (A-D) route */
@ -43,6 +57,9 @@ typedef enum {
BGP_EVPN_IP_PREFIX_ROUTE, /* IP Prefix route */
} bgp_evpn_route_type;
RB_HEAD(bgp_es_evi_rb_head, bgp_evpn_es_evi);
RB_PROTOTYPE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node,
bgp_es_evi_rb_cmp);
/*
* Hash table of EVIs. Right now, the only type of EVI supported is with
* VxLAN encapsulation, hence each EVI corresponds to a L2 VNI.
@ -98,47 +115,17 @@ struct bgpevpn {
* this VNI. */
struct bgp_table *route_table;
/* RB tree of ES-EVIs */
struct bgp_es_evi_rb_head es_evi_rb_tree;
/* List of local ESs */
struct list *local_es_evi_list;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgpevpn)
struct evpnes {
/* Ethernet Segment Identifier */
esi_t esi;
/* es flags */
uint16_t flags;
#define EVPNES_LOCAL 0x01
#define EVPNES_REMOTE 0x02
/*
* Id for deriving the RD
* automatically for this ESI
*/
uint16_t rd_id;
/* RD for this VNI. */
struct prefix_rd prd;
/* originator ip address */
struct ipaddr originator_ip;
/* list of VTEPs in the same site */
struct list *vtep_list;
/*
* Route table for EVPN routes for
* this ESI. - type4 routes
*/
struct bgp_table *route_table;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(evpnes)
/* Mapping of Import RT to VNIs.
* The Import RTs of all VNIs are maintained in a hash table with each
* RT linking to all VNIs that will import routes matching this RT.
@ -330,6 +317,16 @@ static inline void encode_es_rt_extcomm(struct ecommunity_val *eval,
memcpy(&eval->val[2], mac, ETH_ALEN);
}
static inline void encode_esi_label_extcomm(struct ecommunity_val *eval,
bool single_active)
{
memset(eval, 0, sizeof(struct ecommunity_val));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL;
if (single_active)
eval->val[2] |= (1 << 0);
}
static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
struct ethaddr *rmac)
{
@ -487,6 +484,47 @@ static inline void build_evpn_type4_prefix(struct prefix_evpn *p,
memcpy(&p->prefix.es_addr.esi, esi, sizeof(esi_t));
}
static inline void build_evpn_type1_prefix(struct prefix_evpn *p,
uint32_t eth_tag,
esi_t *esi,
struct in_addr originator_ip)
{
memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_EVPN;
p->prefixlen = EVPN_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_AD_ROUTE;
p->prefix.ead_addr.eth_tag = eth_tag;
p->prefix.ead_addr.ip_prefix_length = IPV4_MAX_BITLEN;
p->prefix.ead_addr.ip.ipa_type = IPADDR_V4;
p->prefix.ead_addr.ip.ipaddr_v4 = originator_ip;
memcpy(&p->prefix.ead_addr.esi, esi, sizeof(esi_t));
}
static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p,
const struct prefix_evpn *vni_p)
{
memcpy(global_p, vni_p, sizeof(*global_p));
global_p->prefix.ead_addr.ip_prefix_length = 0;
global_p->prefix.ead_addr.ip.ipa_type = 0;
global_p->prefix.ead_addr.ip.ipaddr_v4.s_addr = 0;
}
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
struct prefix_evpn *vni_p,
const struct prefix_evpn *global_p,
struct in_addr originator_ip)
{
memcpy(vni_p, global_p, sizeof(*vni_p));
vni_p->prefix.ead_addr.ip_prefix_length = IPV4_MAX_BITLEN;
vni_p->prefix.ead_addr.ip.ipa_type = IPADDR_V4;
vni_p->prefix.ead_addr.ip.ipaddr_v4 = originator_ip;
return vni_p;
}
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
safi_t safi)
{
@ -511,11 +549,6 @@ static inline void es_get_system_mac(esi_t *esi,
memcpy(mac, &esi->val[1], ETH_ALEN);
}
static inline int is_es_local(struct evpnes *es)
{
return CHECK_FLAG(es->flags, EVPNES_LOCAL) ? 1 : 0;
}
static inline bool bgp_evpn_is_svi_macip_enabled(struct bgpevpn *vpn)
{
struct bgp *bgp_evpn = NULL;
@ -526,6 +559,8 @@ static inline bool bgp_evpn_is_svi_macip_enabled(struct bgpevpn *vpn)
vpn->advertise_svi_macip);
}
extern struct zclient *zclient;
extern void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf,
afi_t afi, safi_t safi,
bool add);
@ -563,10 +598,18 @@ extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
vrf_id_t tenant_vrf_id,
struct in_addr mcast_grp);
extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
extern struct evpnes *bgp_evpn_lookup_es(struct bgp *bgp, esi_t *esi);
extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni);
extern int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn);
extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_dest *dest,
struct bgp_path_info **pi);
int vni_list_cmp(void *p1, void *p2);
extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_node *rn);
extern struct bgp_node *bgp_global_evpn_node_get(
struct bgp_table *table, afi_t afi, safi_t safi,
const struct prefix_evpn *evp, struct prefix_rd *prd);
extern struct bgp_node *bgp_global_evpn_node_lookup(
struct bgp_table *table, afi_t afi, safi_t safi,
const struct prefix_evpn *evp, struct prefix_rd *prd);
#endif /* _BGP_EVPN_PRIVATE_H */

View file

@ -33,6 +33,7 @@
#endif
#define RD_ADDRSTRLEN 28
#define RD_BYTES 8
struct rd_as {
uint16_t type;

View file

@ -99,6 +99,7 @@ enum bgp_show_adj_route_type {
#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT -12
#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT -13
#define BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY -14
#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE -15
#define BGP_NLRI_PARSE_ERROR -32
/* Ancillary information to struct bgp_path_info,

View file

@ -56,11 +56,11 @@
#include "bgpd/rfapi/vnc_export_bgp.h"
#endif
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_labelpool.h"
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mac.h"
/* All information about zebra. */
@ -2499,17 +2499,14 @@ static void bgp_zebra_connected(struct zclient *zclient)
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
}
static int bgp_zebra_process_local_es(ZAPI_CALLBACK_ARGS)
static int bgp_zebra_process_local_es_add(ZAPI_CALLBACK_ARGS)
{
esi_t esi;
struct bgp *bgp = NULL;
struct stream *s = NULL;
char buf[ESI_STR_LEN];
char buf1[INET6_ADDRSTRLEN];
struct ipaddr originator_ip;
memset(&esi, 0, sizeof(esi_t));
memset(&originator_ip, 0, sizeof(struct ipaddr));
struct in_addr originator_ip;
uint8_t active;
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
@ -2517,18 +2514,70 @@ static int bgp_zebra_process_local_es(ZAPI_CALLBACK_ARGS)
s = zclient->ibuf;
stream_get(&esi, s, sizeof(esi_t));
stream_get(&originator_ip, s, sizeof(struct ipaddr));
originator_ip.s_addr = stream_get_ipv4(s);
active = stream_getc(s);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx %s ESI %s originator-ip %s",
(cmd == ZEBRA_LOCAL_ES_ADD) ? "add" : "del",
esi_to_str(&esi, buf, sizeof(buf)),
ipaddr2str(&originator_ip, buf1, sizeof(buf1)));
zlog_debug("Rx add ESI %s originator-ip %s active %u",
esi_to_str(&esi, buf, sizeof(buf)),
inet_ntoa(originator_ip),
active);
if (cmd == ZEBRA_LOCAL_ES_ADD)
bgp_evpn_local_es_add(bgp, &esi, &originator_ip);
bgp_evpn_local_es_add(bgp, &esi, originator_ip, active);
return 0;
}
static int bgp_zebra_process_local_es_del(ZAPI_CALLBACK_ARGS)
{
esi_t esi;
struct bgp *bgp = NULL;
struct stream *s = NULL;
char buf[ESI_STR_LEN];
memset(&esi, 0, sizeof(esi_t));
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
s = zclient->ibuf;
stream_get(&esi, s, sizeof(esi_t));
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx del ESI %s",
esi_to_str(&esi, buf, sizeof(buf)));
bgp_evpn_local_es_del(bgp, &esi);
return 0;
}
static int bgp_zebra_process_local_es_evi(ZAPI_CALLBACK_ARGS)
{
esi_t esi;
vni_t vni;
struct bgp *bgp;
struct stream *s;
char buf[ESI_STR_LEN];
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
s = zclient->ibuf;
stream_get(&esi, s, sizeof(esi_t));
vni = stream_getl(s);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx %s ESI %s VNI %u",
ZEBRA_VNI_ADD ? "add" : "del",
esi_to_str(&esi, buf, sizeof(buf)), vni);
if (cmd == ZEBRA_LOCAL_ES_EVI_ADD)
bgp_evpn_local_es_evi_add(bgp, &esi, vni);
else
bgp_evpn_local_es_del(bgp, &esi, &originator_ip);
bgp_evpn_local_es_evi_del(bgp, &esi, vni);
return 0;
}
@ -2628,6 +2677,8 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS)
uint8_t flags = 0;
uint32_t seqnum = 0;
int state = 0;
char buf2[ESI_STR_LEN];
esi_t esi;
memset(&ip, 0, sizeof(ip));
s = zclient->ibuf;
@ -2651,6 +2702,7 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS)
if (cmd == ZEBRA_MACIP_ADD) {
flags = stream_getc(s);
seqnum = stream_getl(s);
stream_get(&esi, s, sizeof(esi_t));
} else {
state = stream_getl(s);
}
@ -2660,15 +2712,15 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u state %d",
zlog_debug("%u:Recv MACIP %s f 0x%x MAC %s IP %s VNI %u seq %u state %d ESI %s",
vrf_id, (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
flags, prefix_mac2str(&mac, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum,
state);
state, esi_to_str(&esi, buf2, sizeof(buf2)));
if (cmd == ZEBRA_MACIP_ADD)
return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip,
flags, seqnum);
flags, seqnum, &esi);
else
return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state);
}
@ -2801,9 +2853,11 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance)
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
zclient->fec_update = bgp_read_fec_update;
zclient->local_es_add = bgp_zebra_process_local_es;
zclient->local_es_del = bgp_zebra_process_local_es;
zclient->local_es_add = bgp_zebra_process_local_es_add;
zclient->local_es_del = bgp_zebra_process_local_es_del;
zclient->local_vni_add = bgp_zebra_process_local_vni;
zclient->local_es_evi_add = bgp_zebra_process_local_es_evi;
zclient->local_es_evi_del = bgp_zebra_process_local_es_evi;
zclient->local_vni_del = bgp_zebra_process_local_vni;
zclient->local_macip_add = bgp_zebra_process_local_macip;
zclient->local_macip_del = bgp_zebra_process_local_macip;

View file

@ -87,6 +87,7 @@
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mac.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
@ -6939,6 +6940,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
/* mpls label dynamic allocation pool */
bgp_lp_init(bm->master, &bm->labelpool);
bgp_evpn_mh_init();
QOBJ_REG(bm, bgp_master);
}
@ -7138,6 +7140,7 @@ void bgp_terminate(void)
BGP_TIMER_OFF(bm->t_rmap_update);
bgp_mac_finish();
bgp_evpn_mh_finish();
}
struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,

View file

@ -165,6 +165,9 @@ struct bgp_master {
/* How big should we set the socket buffer size */
uint32_t socket_buffer;
/* EVPN multihoming */
struct bgp_evpn_mh_info *mh_info;
bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
@ -661,9 +664,6 @@ struct bgp {
struct bgp_pbr_config *bgp_pbr_cfg;
/* local esi hash table */
struct hash *esihash;
/* Count of peers in established state */
uint32_t established_peers;

View file

@ -54,6 +54,7 @@ extern "C" {
#define MAX_ESI {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
#define EVPN_ETH_TAG_BYTES 4
#define ESI_BYTES 10
#define ESI_STR_LEN (3 * ESI_BYTES)