bgpd: program mac-ip routes in matching vrfs

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
mitesh 2017-10-11 01:32:54 -07:00 committed by Mitesh Kanjariya
parent 10ebe1ab54
commit d3135ba31d
9 changed files with 411 additions and 5 deletions

View File

@ -782,6 +782,95 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
bgp_info_delete(rn, old_local); bgp_info_delete(rn, old_local);
} }
/*
* Calculate the best path for an EVPN route. Install/update best path in zebra,
* if appropriate.
*/
static int evpn_vrf_route_select_install(struct bgp *bgp_vrf,
struct bgp_node *rn,
struct prefix *p,
afi_t afi,
safi_t safi)
{
struct bgp_info *old_select, *new_select;
struct bgp_info_pair old_and_new;
int ret = 0;
/* Compute the best path. */
bgp_best_selection(bgp_vrf, rn, &bgp_vrf->maxpaths[afi][safi],
&old_and_new, afi, safi);
old_select = old_and_new.old;
new_select = old_and_new.new;
/* If the best path hasn't changed - see if there is still something to
* update
* to zebra RIB.
*/
if (old_select && old_select == new_select
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_NORMAL
&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
&& !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)
&& !bgp_vrf->addpath_tx_used[afi][safi]) {
if (bgp_zebra_has_route_changed(rn, old_select))
bgp_zebra_announce(rn, p, old_select, bgp_vrf,
afi, safi);
UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(rn);
return ret;
}
/* If the user did a "clear" this flag will be set */
UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR);
/* bestpath has changed; update relevant fields and install or uninstall
* into the zebra RIB.
*/
if (old_select || new_select)
bgp_bump_version(rn);
if (old_select)
bgp_info_unset_flag(rn, old_select, BGP_INFO_SELECTED);
if (new_select) {
bgp_info_set_flag(rn, new_select, BGP_INFO_SELECTED);
bgp_info_unset_flag(rn, new_select, BGP_INFO_ATTR_CHANGED);
UNSET_FLAG(new_select->flags, BGP_INFO_MULTIPATH_CHG);
}
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL) {
bgp_zebra_announce(rn, p, new_select, bgp_vrf,
afi, safi);
/* If an old best existed and it was a "local" route, the only
* reason
* it would be supplanted is due to MAC mobility procedures. So,
* we
* need to do an implicit delete and withdraw that route from
* peers.
*/
/*if (old_select && old_select->peer == bgp_vrf->peer_self
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_STATIC) {
//evpn_delete_old_local_route(bgp, vpn, rn, old_select);
}*/ //TODO_MITESH: probably not needed for vrf routes, think!!
} else {
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_NORMAL) {
bgp_zebra_withdraw(p, old_select, safi);
}
}
/* Clear any route change flags. */
bgp_zebra_clear_route_change_flags(rn);
/* Reap old select bgp_info, if it has been removed */
if (old_select && CHECK_FLAG(old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap(rn, old_select);
return ret;
}
/* /*
* Calculate the best path for an EVPN route. Install/update best path in zebra, * Calculate the best path for an EVPN route. Install/update best path in zebra,
* if appropriate. * if appropriate.
@ -1418,6 +1507,88 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
return update_routes_for_vni(bgp, vpn); return update_routes_for_vni(bgp, vpn);
} }
/*
* Install route entry into the VRF routing table and invoke route selection.
*/
static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
struct prefix_evpn *evp,
struct bgp_info *parent_ri)
{
struct bgp_node *rn;
struct bgp_info *ri;
struct attr *attr_new;
int ret;
struct prefix p;
struct prefix *pp = &p;
afi_t afi = 0;
safi_t safi = 0;
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_type2_prefix(evp, pp);
/* Create (or fetch) route within the VRF. */
/* NOTE: There is no RD here. */
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
afi = AFI_IP;
safi = SAFI_UNICAST;
rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
afi = AFI_IP6;
safi = SAFI_UNICAST;
rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
} else
return 0;
/* Check if route entry is already present. */
for (ri = rn->info; ri; ri = ri->next)
if (ri->extra
&& (struct bgp_info *)ri->extra->parent == parent_ri)
break;
if (!ri) {
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(parent_ri->attr);
/* Create new route with its attribute. */
ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
parent_ri->peer, attr_new, rn);
SET_FLAG(ri->flags, BGP_INFO_VALID);
bgp_info_extra_get(ri);
ri->extra->parent = parent_ri;
if (parent_ri->extra)
memcpy(&ri->extra->label, &parent_ri->extra->label,
BGP_LABEL_BYTES);
bgp_info_add(rn, ri);
} else {
if (attrhash_cmp(ri->attr, parent_ri->attr)
&& !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
bgp_unlock_node(rn);
return 0;
}
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(parent_ri->attr);
/* Restore route, if needed. */
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
bgp_info_restore(rn, ri);
/* Mark if nexthop has changed. */
if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop))
SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED);
/* Unintern existing, set to new. */
bgp_attr_unintern(&ri->attr);
ri->attr = attr_new;
ri->uptime = bgp_clock();
}
/* Perform route selection and update zebra, if required. */
ret = evpn_vrf_route_select_install(bgp_vrf, rn, pp, afi, safi);
return ret;
}
/* /*
* Install route entry into the VNI routing table and invoke route selection. * Install route entry into the VNI routing table and invoke route selection.
*/ */
@ -1484,6 +1655,61 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
return ret; return ret;
} }
/*
* Uninstall route entry from the VRF routing table and send message
* to zebra, if appropriate.
*/
static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
struct prefix_evpn *evp,
struct bgp_info *parent_ri)
{
struct bgp_node *rn;
struct bgp_info *ri;
int ret;
struct prefix p;
struct prefix *pp = &p;
afi_t afi = 0;
safi_t safi = 0;
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_type2_prefix(evp, pp);
/* Locate route within the VRF. */
/* NOTE: There is no RD here. */
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
afi = AFI_IP;
safi = SAFI_UNICAST;
rn = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
} else {
afi = AFI_IP6;
safi = SAFI_UNICAST;
rn = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
}
if (!rn)
return 0;
/* Find matching route entry. */
for (ri = rn->info; ri; ri = ri->next)
if (ri->extra
&& (struct bgp_info *)ri->extra->parent == parent_ri)
break;
if (!ri)
return 0;
/* Mark entry for deletion */
bgp_info_delete(rn, ri);
/* Perform route selection and update zebra, if required. */
ret = evpn_vrf_route_select_install(bgp_vrf, rn, pp, afi, safi);
/* Unlock route node. */
bgp_unlock_node(rn);
return ret;
}
/* /*
* Uninstall route entry from the VNI routing table and send message * Uninstall route entry from the VNI routing table and send message
* to zebra, if appropriate. * to zebra, if appropriate.
@ -1706,6 +1932,45 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
0); 0);
} }
/*
* Install or uninstall route in matching VRFs (list).
*/
static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
safi_t safi, struct prefix_evpn *evp,
struct bgp_info *ri,
struct list *vrfs, int install)
{
char buf[PREFIX2STR_BUFFER];
struct bgp *bgp_vrf;
struct listnode *node, *nnode;
/* Only type-2 routes go into a VRF */
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
return 0;
for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
int ret;
if (install)
ret = install_evpn_route_entry_in_vrf(bgp_vrf,
evp, ri);
else
ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf,
evp, ri);
if (ret) {
zlog_err("%u: Failed to %s prefix %s in VRF %s",
bgp_def->vrf_id,
install ? "install" : "uninstall",
prefix2str(evp, buf, sizeof(buf)),
vrf_id_to_name(bgp_vrf->vrf_id));
return ret;
}
}
return 0;
}
/* /*
* Install or uninstall route in matching VNIs (list). * Install or uninstall route in matching VNIs (list).
*/ */
@ -1777,7 +2042,8 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
u_char type, sub_type; u_char type, sub_type;
struct ecommunity_val *eval; struct ecommunity_val *eval;
struct ecommunity_val eval_tmp; struct ecommunity_val eval_tmp;
struct irt_node *irt; struct irt_node *irt; /* import rt for l2vni */
struct vrf_irt_node *vrf_irt; /* import rt for l3vni */
/* Only deal with RTs */ /* Only deal with RTs */
pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
@ -1788,12 +2054,18 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
if (sub_type != ECOMMUNITY_ROUTE_TARGET) if (sub_type != ECOMMUNITY_ROUTE_TARGET)
continue; continue;
/* Are we interested in this RT? */ /* Import route into matching l2-vnis */
irt = lookup_import_rt(bgp, eval); irt = lookup_import_rt(bgp, eval);
if (irt && irt->vnis) if (irt && irt->vnis)
install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri, install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
irt->vnis, import); irt->vnis, import);
/* Import route into matching l3-vnis (vrfs) */
vrf_irt = lookup_vrf_import_rt(eval);
if (vrf_irt && vrf_irt->vrfs)
install_uninstall_route_in_vrfs(bgp, afi, safi, evp, ri,
vrf_irt->vrfs, import);
/* Also check for non-exact match. In this, we mask out the AS /* Also check for non-exact match. In this, we mask out the AS
* and * and
* only check on the local-admin sub-field. This is to * only check on the local-admin sub-field. This is to
@ -1801,16 +2073,22 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
* VNI as the RT for EBGP peering too. * VNI as the RT for EBGP peering too.
*/ */
irt = NULL; irt = NULL;
vrf_irt = NULL;
if (type == ECOMMUNITY_ENCODE_AS if (type == ECOMMUNITY_ENCODE_AS
|| type == ECOMMUNITY_ENCODE_AS4 || type == ECOMMUNITY_ENCODE_AS4
|| type == ECOMMUNITY_ENCODE_IP) { || type == ECOMMUNITY_ENCODE_IP) {
memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE); memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
mask_ecom_global_admin(&eval_tmp, eval); mask_ecom_global_admin(&eval_tmp, eval);
irt = lookup_import_rt(bgp, &eval_tmp); irt = lookup_import_rt(bgp, &eval_tmp);
vrf_irt = lookup_vrf_import_rt(&eval_tmp);
} }
if (irt && irt->vnis) if (irt && irt->vnis)
install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri, install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
irt->vnis, import); irt->vnis, import);
if (vrf_irt && vrf_irt->vrfs)
install_uninstall_route_in_vrfs(bgp, afi, safi, evp,
ri, vrf_irt->vrfs,
import);
} }
return 0; return 0;

View File

@ -258,6 +258,25 @@ static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
eval->val[7] = seq & 0xff; eval->val[7] = seq & 0xff;
} }
static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
struct prefix *ip)
{
memset(ip, 0, sizeof(struct prefix));
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
ip->family = AF_INET;
ip->prefixlen = IPV4_MAX_BITLEN;
memcpy(&(ip->u.prefix4),
&(evp->prefix.ip.ip),
IPV4_MAX_BYTELEN);
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
ip->family = AF_INET6;
ip->prefixlen = IPV6_MAX_BITLEN;
memcpy(&(ip->u.prefix6),
&(evp->prefix.ip.ip),
IPV6_MAX_BYTELEN);
}
}
static inline void build_evpn_type2_prefix(struct prefix_evpn *p, static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
struct ethaddr *mac, struct ethaddr *mac,
struct ipaddr *ip) struct ipaddr *ip)

View File

@ -411,6 +411,52 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_object_add(json, "exportRts", json_export_rtl); json_object_object_add(json, "exportRts", json_export_rtl);
} }
static void evpn_show_vrf_routes(struct vty *vty,
struct bgp *bgp_vrf)
{
struct bgp *bgp_def = NULL;
struct bgp_node *rn;
struct bgp_info *ri;
int header = 1;
u_int32_t prefix_cnt, path_cnt;
prefix_cnt = path_cnt = 0;
bgp_def = bgp_get_default();
if (!bgp_def)
return;
for (rn = bgp_table_top(bgp_vrf->rib[AFI_L2VPN][SAFI_EVPN]); rn;
rn = bgp_route_next(rn)) {
char prefix_str[BUFSIZ];
bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
sizeof(prefix_str));
if (rn->info) {
/* Overall header/legend displayed once. */
if (header) {
bgp_evpn_show_route_header(vty, bgp_def, NULL);
header = 0;
}
prefix_cnt++;
}
/* For EVPN, the prefix is displayed for each path (to fit in
* with code that already exists).
*/
for (ri = rn->info; ri; ri = ri->next) {
route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, NULL);
path_cnt++;
}
}
if (prefix_cnt == 0)
vty_out(vty, "No EVPN prefixes exist for this VRF");
else
vty_out(vty, "\nDisplayed %u prefixes (%u paths)",
prefix_cnt, path_cnt);
}
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
struct vty *vty, struct in_addr vtep_ip, struct vty *vty, struct in_addr vtep_ip,
json_object *json) json_object *json)
@ -2640,6 +2686,33 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
/*
* Display per-VRF EVPN routing table.
*/
DEFUN(show_bgp_l2vpn_evpn_route_vrf, show_bgp_l2vpn_evpn_route_vrf_cmd,
"show bgp l2vpn evpn route vrf VRFNAME",
SHOW_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
"EVPN route information\n"
"VRF\n"
"VRF Name\n")
{
int vrf_idx = 6;
char *vrf_name = NULL;
struct bgp *bgp_vrf = NULL;
vrf_name = argv[vrf_idx]->arg;
bgp_vrf = bgp_lookup_by_name(vrf_name);
if (!bgp_vrf)
return CMD_WARNING;
evpn_show_vrf_routes(vty, bgp_vrf);
return CMD_SUCCESS;
}
/* /*
* Display per-VNI EVPN routing table. * Display per-VNI EVPN routing table.
*/ */
@ -3697,6 +3770,7 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vrf_cmd);
install_element(VIEW_NODE, install_element(VIEW_NODE,
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd); &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);

View File

@ -1015,6 +1015,12 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (info->sub_type == BGP_ROUTE_AGGREGATE) if (info->sub_type == BGP_ROUTE_AGGREGATE)
zapi_route_set_blackhole(&api, BLACKHOLE_NULL); zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
/* If it is an EVPN route mark as such.
* Currently presence of rmac in attr denotes
* this is an EVPN type-2 route */
if (!is_zero_mac(&(info->attr->rmac)))
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_TYPE2_ROUTE);
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|| info->sub_type == BGP_ROUTE_AGGREGATE) { || info->sub_type == BGP_ROUTE_AGGREGATE) {
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
@ -1072,7 +1078,13 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
api_nh = &api.nexthops[valid_nh_count]; api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv4 = *nexthop; api_nh->gate.ipv4 = *nexthop;
api_nh->type = NEXTHOP_TYPE_IPV4;
/* EVPN type-2 routes are
programmed as onlink on l3-vni SVI */
if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_TYPE2_ROUTE))
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
else
api_nh->type = NEXTHOP_TYPE_IPV4;
} else { } else {
ifindex_t ifindex; ifindex_t ifindex;
struct in6_addr *nexthop; struct in6_addr *nexthop;

View File

@ -409,6 +409,7 @@ extern const char *zserv_command_string(unsigned int command);
#define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_SCOPE_LINK 0x100 #define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200 #define ZEBRA_FLAG_FIB_OVERRIDE 0x200
#define ZEBRA_FLAG_EVPN_TYPE2_ROUTE 0x400
/* ZEBRA_FLAG_BLACKHOLE was 0x04 */ /* ZEBRA_FLAG_BLACKHOLE was 0x04 */
/* ZEBRA_FLAG_REJECT was 0x80 */ /* ZEBRA_FLAG_REJECT was 0x80 */

View File

@ -259,7 +259,8 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
/*Pending: need to think if null ifp here is ok during bootup? /*Pending: need to think if null ifp here is ok during bootup?
There was a crash because ifp here was coming to be NULL */ There was a crash because ifp here was coming to be NULL */
if (ifp) if (ifp)
if (connected_is_unnumbered(ifp)) { if (connected_is_unnumbered(ifp) ||
CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_TYPE2_ROUTE)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
} }

View File

@ -6084,3 +6084,15 @@ void zebra_vxlan_ns_disable(struct zebra_ns *zns)
{ {
hash_free(zns->l3vni_table); hash_free(zns->l3vni_table);
} }
/* get the l3vni svi ifindex */
ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
{
zebra_l3vni_t *zl3vni = NULL;
zl3vni = zl3vni_from_vrf(vrf_id);
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
return 0;
return zl3vni->svi_if->ifindex;
}

View File

@ -51,6 +51,7 @@ is_evpn_enabled()
#define VNI_STR_LEN 32 #define VNI_STR_LEN 32
extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
extern int zebra_vxlan_vrf_delete(struct zebra_vrf *); extern int zebra_vxlan_vrf_delete(struct zebra_vrf *);
extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, u_char use_json); vni_t vni, u_char use_json);

View File

@ -1149,6 +1149,7 @@ static int zread_route_add(struct zserv *client, u_short length,
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
for (i = 0; i < api.nexthop_num; i++) { for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i]; api_nh = &api.nexthops[i];
ifindex_t ifindex = 0;
switch (api_nh->type) { switch (api_nh->type) {
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
@ -1160,9 +1161,16 @@ static int zread_route_add(struct zserv *client, u_short length,
re, &api_nh->gate.ipv4, NULL); re, &api_nh->gate.ipv4, NULL);
break; break;
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
if (CHECK_FLAG(api.flags,
ZEBRA_FLAG_EVPN_TYPE2_ROUTE)) {
ifindex =
get_l3vni_svi_ifindex(zvrf_id(zvrf));
} else {
ifindex = api_nh->ifindex;
}
nexthop = route_entry_nexthop_ipv4_ifindex_add( nexthop = route_entry_nexthop_ipv4_ifindex_add(
re, &api_nh->gate.ipv4, NULL, re, &api_nh->gate.ipv4, NULL,
api_nh->ifindex); ifindex);
break; break;
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
nexthop = route_entry_nexthop_ipv6_add( nexthop = route_entry_nexthop_ipv6_add(