*: EVPN symmetric routing for IPv6 tenant routes

Implement support for EVPN symmetric routing for IPv6 routes. The next hop
for EVPN routes is the IP address of the remote VTEP which is only an IPv4
address. This means that for IPv6 symmetric routing, there will be IPv6
destinations with IPv4 next hops. To make this work, the IPv4 next hops are
converted into IPv4-mapped IPv6 addresses.

As part of support, ensure that "L3" route-targets are not announced with
IPv6 link-local addresses so that they won't be installed in the routing
table.

Signed-off-by: Vivek Venkatraman vivek@cumulusnetworks.com
Reviewed-by: Mitesh Kanjariya mitesh@cumulusnetworks.com
Reviewed-by: Donald Sharp sharpd@cumulusnetworks.com
This commit is contained in:
vivek 2018-02-28 02:07:23 +00:00
parent f894c3b2ea
commit 1ec31309bb
5 changed files with 144 additions and 90 deletions

View File

@ -478,6 +478,17 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
bgp_evpn_derive_auto_rt_export(bgp, vpn); bgp_evpn_derive_auto_rt_export(bgp, vpn);
} }
/*
* Convert nexthop (remote VTEP IP) into an IPv6 address.
*/
static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
{
if (BGP_ATTR_NEXTHOP_AFI_IP6(attr))
return;
ipv4_to_ipv4_mapped_ipv6(&attr->mp_nexthop_global, attr->nexthop);
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
}
/* /*
* Add (update) or delete MACIP from zebra. * Add (update) or delete MACIP from zebra.
*/ */
@ -626,17 +637,17 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
} }
/* /*
* Build extended communities for EVPN route. RT and ENCAP are * Build extended communities for EVPN route.
* applicable to all routes. * This function is applicable for type-2 and type-3 routes. The layer-2 RT
* TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops. * and ENCAP extended communities are applicable for all routes.
* This means that we can't do symmetric routing for ipv6 hosts routes * The default gateway extended community and MAC mobility (sticky) extended
* in the same way as ipv4 host routes. * community are added as needed based on passed settings - only for type-2
* We wont attach l3-vni related RTs for ipv6 routes. * routes. Likewise, the layer-3 RT and Router MAC extended communities are
* For now, We will only adevrtise ipv4 host routes * added, if present, based on passed settings - only for non-link-local
* with L3-VNI related ext-comm. * type-2 routes.
*/ */
static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
afi_t afi) int add_l3_ecomm)
{ {
struct ecommunity ecom_encap; struct ecommunity ecom_encap;
struct ecommunity ecom_sticky; struct ecommunity ecom_sticky;
@ -666,11 +677,10 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom); attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
/* /* Add the export RTs for L3VNI if told to - caller determines
* only attach l3-vni export rts for ipv4 address family and if we are * when this should be done.
* advertising both the labels in type-2 routes
*/ */
if (afi == AFI_IP && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { if (add_l3_ecomm) {
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn); vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) { if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
@ -681,6 +691,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
} }
} }
/* Add MAC mobility (sticky) if needed. */
if (attr->sticky) { if (attr->sticky) {
seqnum = 0; seqnum = 0;
memset(&ecom_sticky, 0, sizeof(ecom_sticky)); memset(&ecom_sticky, 0, sizeof(ecom_sticky));
@ -691,12 +702,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
ecommunity_merge(attr->ecommunity, &ecom_sticky); ecommunity_merge(attr->ecommunity, &ecom_sticky);
} }
/* /* Add RMAC, if told to. */
* only attach l3-vni rmac for ipv4 address family and if we are if (add_l3_ecomm) {
* advertising both the labels in type-2 routes
*/
if (afi == AFI_IP && !is_zero_mac(&attr->rmac) &&
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
memset(&ecom_rmac, 0, sizeof(ecom_rmac)); memset(&ecom_rmac, 0, sizeof(ecom_rmac));
encode_rmac_extcomm(&eval_rmac, &attr->rmac); encode_rmac_extcomm(&eval_rmac, &attr->rmac);
ecom_rmac.size = 1; ecom_rmac.size = 1;
@ -705,6 +712,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
&ecom_rmac); &ecom_rmac);
} }
/* Add default gateway, if needed. */
if (attr->default_gw) { if (attr->default_gw) {
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
encode_default_gw_extcomm(&eval_default_gw); encode_default_gw_extcomm(&eval_default_gw);
@ -1269,6 +1277,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_node *rn; struct bgp_node *rn;
struct attr attr; struct attr attr;
struct attr *attr_new; struct attr *attr_new;
int add_l3_ecomm = 0;
struct bgp_info *ri; struct bgp_info *ri;
afi_t afi = AFI_L2VPN; afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN; safi_t safi = SAFI_EVPN;
@ -1288,15 +1297,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
/* router mac is only needed for type-2 and type-5 routes */ /* router mac is only needed for type-2 routes here. */
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
bgpevpn_get_rmac(vpn, &attr.rmac); bgpevpn_get_rmac(vpn, &attr.rmac);
vni2label(vpn->vni, &(attr.label)); vni2label(vpn->vni, &(attr.label));
/* Set up RT and ENCAP extended community. */ /* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
build_evpn_route_extcomm(vpn, &attr, * IPv4 or IPv6 global addresses and we're advertising L3VNI with
IS_EVPN_PREFIX_IPADDR_V4(p) ? * these routes.
AFI_IP : AFI_IP6); */
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
(IS_EVPN_PREFIX_IPADDR_V4(p) ||
!IN6_IS_ADDR_LINKLOCAL(&p->prefix.ip.ipaddr_v6)) &&
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
add_l3_ecomm = 1;
/* Set up extended community. */
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
/* First, create (or fetch) route node within the VNI. */ /* First, create (or fetch) route node within the VNI. */
/* NOTE: There is no RD here. */ /* NOTE: There is no RD here. */
@ -1478,22 +1495,20 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
struct attr attr; struct attr attr;
struct attr attr_sticky; struct attr attr_sticky;
struct attr attr_def_gw; struct attr attr_def_gw;
struct attr attr_ip6; struct attr attr_ip6_ll;
struct attr attr_sticky_ip6;
struct attr attr_def_gw_ip6;
struct attr *attr_new; struct attr *attr_new;
int add_l3_ecomm = 0;
afi = AFI_L2VPN; afi = AFI_L2VPN;
safi = SAFI_EVPN; safi = SAFI_EVPN;
memset(&attr, 0, sizeof(struct attr)); memset(&attr, 0, sizeof(struct attr));
memset(&attr_sticky, 0, sizeof(struct attr)); memset(&attr_sticky, 0, sizeof(struct attr));
memset(&attr_def_gw, 0, sizeof(struct attr)); memset(&attr_def_gw, 0, sizeof(struct attr));
memset(&attr_ip6, 0, sizeof(struct attr)); memset(&attr_ip6_ll, 0, sizeof(struct attr));
memset(&attr_sticky_ip6, 0, sizeof(struct attr));
memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
/* Build path-attribute - all type-2 routes for this VNI will share the /* Build path-attribute - multiple type-2 routes for this VNI will share
* same path attribute. * the same path attribute, but we need separate structures for sticky
* MACs, default gateway and IPv6 link-local addresses (no L3 RT/RMAC).
*/ */
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
@ -1512,31 +1527,21 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_def_gw.default_gw = 1; attr_def_gw.default_gw = 1;
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac); bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_ip6_ll, BGP_ORIGIN_IGP);
bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP); attr_ip6_ll.nexthop = vpn->originator_ip;
bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP); attr_ip6_ll.mp_nexthop_global_in = vpn->originator_ip;
attr_ip6.nexthop = vpn->originator_ip; attr_ip6_ll.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_ip6.mp_nexthop_global_in = vpn->originator_ip;
attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
bgpevpn_get_rmac(vpn, &attr_ip6.rmac);
attr_sticky_ip6.nexthop = vpn->originator_ip;
attr_sticky_ip6.mp_nexthop_global_in = vpn->originator_ip;
attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_sticky_ip6.sticky = 1;
bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
attr_def_gw_ip6.nexthop = vpn->originator_ip;
attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_def_gw_ip6.default_gw = 1;
bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
/* Set up RT, ENCAP and sticky MAC extended community. */ /* Add L3 VNI RTs and RMAC for non IPv6 link-local attributes if
build_evpn_route_extcomm(vpn, &attr, AFI_IP); * using L3 VNI for type-2 routes also.
build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP); */
build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP); if (CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6); add_l3_ecomm = 1;
build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP); build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
build_evpn_route_extcomm(vpn, &attr_sticky, add_l3_ecomm);
build_evpn_route_extcomm(vpn, &attr_def_gw, add_l3_ecomm);
build_evpn_route_extcomm(vpn, &attr_ip6_ll, 0);
/* Walk this VNI's route table and update local type-2 routes. For any /* Walk this VNI's route table and update local type-2 routes. For any
* routes updated, update corresponding entry in the global table too. * routes updated, update corresponding entry in the global table too.
@ -1550,7 +1555,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue; continue;
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) { if (IS_EVPN_PREFIX_IPADDR_V6(evp) &&
IN6_IS_ADDR_LINKLOCAL(&evp->prefix.ip.ipaddr_v6))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_ip6_ll, 0, 1, &ri, 0);
else {
if (evpn_route_is_sticky(bgp, rn)) if (evpn_route_is_sticky(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn, update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_sticky, 0, 1, &attr_sticky, 0, 1,
@ -1562,19 +1571,6 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
else else
update_evpn_route_entry(bgp, vpn, afi, safi, rn, update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr, 0, 1, &ri, 0); &attr, 0, 1, &ri, 0);
} else {
if (evpn_route_is_sticky(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_sticky_ip6, 0, 1,
&ri, 0);
else if (evpn_route_is_def_gw(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_def_gw_ip6, 0, 1,
&ri, 0);
else
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_ip6, 0, 1,
&ri, 0);
} }
/* If a local route exists for this prefix, we need to update /* If a local route exists for this prefix, we need to update
@ -1605,11 +1601,9 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
/* Unintern temporary. */ /* Unintern temporary. */
aspath_unintern(&attr.aspath); aspath_unintern(&attr.aspath);
aspath_unintern(&attr_ip6.aspath);
aspath_unintern(&attr_sticky.aspath); aspath_unintern(&attr_sticky.aspath);
aspath_unintern(&attr_sticky_ip6.aspath);
aspath_unintern(&attr_def_gw.aspath); aspath_unintern(&attr_def_gw.aspath);
aspath_unintern(&attr_def_gw_ip6.aspath); aspath_unintern(&attr_ip6_ll.aspath);
return 0; return 0;
} }
@ -1801,6 +1795,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
{ {
struct bgp_node *rn; struct bgp_node *rn;
struct bgp_info *ri; struct bgp_info *ri;
struct attr attr;
struct attr *attr_new; struct attr *attr_new;
int ret = 0; int ret = 0;
struct prefix p; struct prefix p;
@ -1836,6 +1831,15 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
} else } else
return 0; return 0;
/* EVPN routes currently only support a IPv4 next hop which corresponds
* to the remote VTEP. When importing into a VRF, if it is IPv6 host
* route, we have to convert the next hop to an IPv4-mapped address
* for the rest of the code to flow through.
*/
bgp_attr_dup(&attr, parent_ri->attr);
if (afi == AFI_IP6)
evpn_convert_nexthop_to_ipv6(&attr);
/* Check if route entry is already present. */ /* Check if route entry is already present. */
for (ri = rn->info; ri; ri = ri->next) for (ri = rn->info; ri; ri = ri->next)
if (ri->extra if (ri->extra
@ -1844,7 +1848,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
if (!ri) { if (!ri) {
/* Add (or update) attribute to hash. */ /* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(parent_ri->attr); attr_new = bgp_attr_intern(&attr);
/* Create new route with its attribute. */ /* Create new route with its attribute. */
ri = info_make(parent_ri->type, parent_ri->sub_type, 0, ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
@ -1859,21 +1863,25 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
} }
bgp_info_add(rn, ri); bgp_info_add(rn, ri);
} else { } else {
if (attrhash_cmp(ri->attr, parent_ri->attr) if (attrhash_cmp(ri->attr, &attr)
&& !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
bgp_unlock_node(rn); bgp_unlock_node(rn);
return 0; return 0;
} }
/* The attribute has changed. */ /* The attribute has changed. */
/* Add (or update) attribute to hash. */ /* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(parent_ri->attr); attr_new = bgp_attr_intern(&attr);
/* Restore route, if needed. */ /* Restore route, if needed. */
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
bgp_info_restore(rn, ri); bgp_info_restore(rn, ri);
/* Mark if nexthop has changed. */ /* Mark if nexthop has changed. */
if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) if ((afi == AFI_IP &&
!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) ||
(afi == AFI_IP6 &&
!IPV6_ADDR_SAME(&ri->attr->mp_nexthop_global,
&attr_new->mp_nexthop_global)))
SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED); SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED);
/* Unintern existing, set to new. */ /* Unintern existing, set to new. */

View File

@ -2780,7 +2780,7 @@ DEFUN (no_bgp_evpn_advertise_type5,
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi); argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi); argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
if (!(afi == AFI_IP) || (afi == AFI_IP6)) { if (!(afi == AFI_IP || afi == AFI_IP6)) {
vty_out(vty, vty_out(vty,
"%%only ipv4 or ipv6 address families are supported"); "%%only ipv4 or ipv6 address families are supported");
return CMD_WARNING; return CMD_WARNING;

View File

@ -85,4 +85,14 @@ static inline char *ipaddr2str(struct ipaddr *ip, char *buf, int size)
} }
return buf; return buf;
} }
static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
struct in_addr in)
{
u_int32_t addr_type = htonl(0xFFFF);
memset(in6, 0, sizeof(struct in6_addr));
memcpy((char *)in6 + 8, &addr_type, sizeof(addr_type));
memcpy((char *)in6 + 12, &in, sizeof(struct in_addr));
}
#endif /* __IPADDR_H__ */ #endif /* __IPADDR_H__ */

View File

@ -305,6 +305,8 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6; nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex; nexthop->ifindex = ifindex;
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
route_entry_nexthop_add(re, nexthop); route_entry_nexthop_add(re, nexthop);
@ -421,6 +423,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
re->nexthop_mtu = 0; re->nexthop_mtu = 0;
} }
/* Next hops (remote VTEPs) for EVPN routes are fully resolved. */
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP))
return 1;
/* Skip nexthops that have been filtered out due to route-map */ /* Skip nexthops that have been filtered out due to route-map */
/* The nexthops are specific to this route and so the same */ /* The nexthops are specific to this route and so the same */
/* nexthop for a different route may not have this flag set */ /* nexthop for a different route may not have this flag set */
@ -858,9 +864,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP; family = AFI_IP;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) if (nexthop_active(AFI_IP, re, nexthop, set, rn))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else if (nexthop_active(AFI_IP, re, nexthop, set, rn))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@ -2548,10 +2552,17 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
struct ipaddr vtep_ip; struct ipaddr vtep_ip;
memset(&vtep_ip, 0, sizeof(struct ipaddr)); memset(&vtep_ip, 0, sizeof(struct ipaddr));
vtep_ip.ipa_type = IPADDR_V4; if (afi == AFI_IP) {
memcpy(&(vtep_ip.ipaddr_v4), vtep_ip.ipa_type = IPADDR_V4;
&(tmp_nh->gate.ipv4), memcpy(&(vtep_ip.ipaddr_v4),
sizeof(struct in_addr)); &(tmp_nh->gate.ipv4),
sizeof(struct in_addr));
} else {
vtep_ip.ipa_type = IPADDR_V6;
memcpy(&(vtep_ip.ipaddr_v6),
&(tmp_nh->gate.ipv6),
sizeof(struct in6_addr));
}
zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac, zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac,
&vtep_ip, p); &vtep_ip, p);
} }

View File

@ -1143,6 +1143,7 @@ static int zread_route_add(struct zserv *client, u_short length,
struct nexthop *nexthop = NULL; struct nexthop *nexthop = NULL;
int i, ret; int i, ret;
vrf_id_t vrf_id = 0; vrf_id_t vrf_id = 0;
struct ipaddr vtep_ip;
s = client->ibuf; s = client->ibuf;
if (zapi_route_decode(s, &api) < 0) if (zapi_route_decode(s, &api) < 0)
@ -1173,9 +1174,7 @@ static int zread_route_add(struct zserv *client, u_short length,
re, &api_nh->gate.ipv4, NULL, re, &api_nh->gate.ipv4, NULL,
re->vrf_id); re->vrf_id);
break; break;
case NEXTHOP_TYPE_IPV4_IFINDEX: { case NEXTHOP_TYPE_IPV4_IFINDEX:
struct ipaddr vtep_ip;
memset(&vtep_ip, 0, sizeof(struct ipaddr)); memset(&vtep_ip, 0, sizeof(struct ipaddr));
if (CHECK_FLAG(api.flags, if (CHECK_FLAG(api.flags,
@ -1208,15 +1207,41 @@ static int zread_route_add(struct zserv *client, u_short length,
&api.prefix); &api.prefix);
} }
break; break;
}
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
nexthop = route_entry_nexthop_ipv6_add( nexthop = route_entry_nexthop_ipv6_add(
re, &api_nh->gate.ipv6, re->vrf_id); re, &api_nh->gate.ipv6, re->vrf_id);
break; break;
case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFINDEX:
memset(&vtep_ip, 0, sizeof(struct ipaddr));
if (CHECK_FLAG(api.flags,
ZEBRA_FLAG_EVPN_ROUTE)) {
ifindex =
get_l3vni_svi_ifindex(vrf_id);
} else {
ifindex = api_nh->ifindex;
}
nexthop = route_entry_nexthop_ipv6_ifindex_add( nexthop = route_entry_nexthop_ipv6_ifindex_add(
re, &api_nh->gate.ipv6, api_nh->ifindex, re, &api_nh->gate.ipv6, ifindex,
re->vrf_id); re->vrf_id);
/* if this an EVPN route entry,
program the nh as neigh
*/
if (CHECK_FLAG(api.flags,
ZEBRA_FLAG_EVPN_ROUTE)) {
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_EVPN_RVTEP);
vtep_ip.ipa_type = IPADDR_V6;
memcpy(&vtep_ip.ipaddr_v6,
&(api_nh->gate.ipv6),
sizeof(struct in6_addr));
zebra_vxlan_evpn_vrf_route_add(
vrf_id,
&api.rmac,
&vtep_ip,
&api.prefix);
}
break; break;
case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_BLACKHOLE:
nexthop = route_entry_nexthop_blackhole_add( nexthop = route_entry_nexthop_blackhole_add(