]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'master' of https://github.com/frrouting/frr into evpn-ipv6-tenant-routing
authorvivek <vivek@cumulusnetworks.com>
Tue, 6 Mar 2018 22:19:24 +0000 (22:19 +0000)
committervivek <vivek@cumulusnetworks.com>
Tue, 6 Mar 2018 22:19:24 +0000 (22:19 +0000)
Conflicts:
zebra/zserv.c

1  2 
bgpd/bgp_evpn.c
lib/ipaddr.h
zebra/zebra_rib.c
zebra/zserv.c

diff --combined bgpd/bgp_evpn.c
index 2271aa100536446c132bd073ee5c34f11b3b101b,e5863e49802b4ba7bb4c602deb5e75c9e97b1467..9a62c525bd96706ac5866141858c12bc4a684691
@@@ -478,17 -478,6 +478,17 @@@ static void derive_rd_rt_for_vni(struc
        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.
   */
@@@ -637,17 -626,17 +637,17 @@@ static void build_evpn_type5_route_extc
  }
  
  /*
 - * Build extended communities for EVPN route. RT and ENCAP are
 - * applicable to all routes.
 - * TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops.
 - * This means that we can't do symmetric routing for ipv6 hosts routes
 - * in the same way as ipv4 host routes.
 - * We wont attach l3-vni related RTs for ipv6 routes.
 - * For now, We will only adevrtise ipv4 host routes
 - * with L3-VNI related ext-comm.
 + * Build extended communities for EVPN route.
 + * This function is applicable for type-2 and type-3 routes. The layer-2 RT
 + * and ENCAP extended communities are applicable for all routes.
 + * The default gateway extended community and MAC mobility (sticky) extended
 + * community are added as needed based on passed settings - only for type-2
 + * routes. Likewise, the layer-3 RT and Router MAC extended communities are
 + * added, if present, based on passed settings - only for non-link-local
 + * type-2 routes.
   */
  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_sticky;
        for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
                attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
  
 -      /*
 -       * only attach l3-vni export rts for ipv4 address family and if we are
 -       * advertising both the labels in type-2 routes
 +      /* Add the export RTs for L3VNI if told to - caller determines
 +       * when this should be done.
         */
 -      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);
                if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
                        for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
                }
        }
  
 +      /* Add MAC mobility (sticky) if needed. */
        if (attr->sticky) {
                seqnum = 0;
                memset(&ecom_sticky, 0, sizeof(ecom_sticky));
                        ecommunity_merge(attr->ecommunity, &ecom_sticky);
        }
  
 -      /*
 -       * only attach l3-vni rmac for ipv4 address family and if we are
 -       * 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)) {
 +      /* Add RMAC, if told to. */
 +      if (add_l3_ecomm) {
                memset(&ecom_rmac, 0, sizeof(ecom_rmac));
                encode_rmac_extcomm(&eval_rmac, &attr->rmac);
                ecom_rmac.size = 1;
                                                    &ecom_rmac);
        }
  
 +      /* Add default gateway, if needed. */
        if (attr->default_gw) {
                memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
                encode_default_gw_extcomm(&eval_default_gw);
@@@ -1277,7 -1269,6 +1277,7 @@@ static int update_evpn_route(struct bg
        struct bgp_node *rn;
        struct attr attr;
        struct attr *attr_new;
 +      int add_l3_ecomm = 0;
        struct bgp_info *ri;
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
        if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE)
                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)
                bgpevpn_get_rmac(vpn, &attr.rmac);
        vni2label(vpn->vni, &(attr.label));
  
 -      /* Set up RT and ENCAP extended community. */
 -      build_evpn_route_extcomm(vpn, &attr,
 -                               IS_EVPN_PREFIX_IPADDR_V4(p) ?
 -                                      AFI_IP : AFI_IP6);
 +      /* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
 +       * IPv4 or IPv6 global addresses and we're advertising L3VNI with
 +       * these routes.
 +       */
 +      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. */
        /* NOTE: There is no RD here. */
@@@ -1495,20 -1478,22 +1495,20 @@@ static int update_all_type2_routes(stru
        struct attr attr;
        struct attr attr_sticky;
        struct attr attr_def_gw;
 -      struct attr attr_ip6;
 -      struct attr attr_sticky_ip6;
 -      struct attr attr_def_gw_ip6;
 +      struct attr attr_ip6_ll;
        struct attr *attr_new;
 +      int add_l3_ecomm = 0;
  
        afi = AFI_L2VPN;
        safi = SAFI_EVPN;
        memset(&attr, 0, sizeof(struct attr));
        memset(&attr_sticky, 0, sizeof(struct attr));
        memset(&attr_def_gw, 0, sizeof(struct attr));
 -      memset(&attr_ip6, 0, sizeof(struct attr));
 -      memset(&attr_sticky_ip6, 0, sizeof(struct attr));
 -      memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
 +      memset(&attr_ip6_ll, 0, sizeof(struct attr));
  
 -      /* Build path-attribute - all type-2 routes for this VNI will share the
 -       * same path attribute.
 +      /* Build path-attribute - multiple type-2 routes for this VNI will share
 +       * 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_sticky, BGP_ORIGIN_IGP);
        attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        attr_def_gw.default_gw = 1;
        bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
 -      bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
 -      bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
 -      bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
 -      attr_ip6.nexthop = vpn->originator_ip;
 -      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. */
 -      build_evpn_route_extcomm(vpn, &attr, AFI_IP);
 -      build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
 -      build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
 -      build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
 -      build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
 -      build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
 +      bgp_attr_default_set(&attr_ip6_ll, BGP_ORIGIN_IGP);
 +      attr_ip6_ll.nexthop = vpn->originator_ip;
 +      attr_ip6_ll.mp_nexthop_global_in = vpn->originator_ip;
 +      attr_ip6_ll.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
 +
 +      /* Add L3 VNI RTs and RMAC for non IPv6 link-local attributes if
 +       * using L3 VNI for type-2 routes also.
 +       */
 +      if (CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
 +              add_l3_ecomm = 1;
 +
 +      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
         * routes updated, update corresponding entry in the global table too.
                if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
                        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))
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &attr_sticky, 0, 1,
                        else
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &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
  
        /* Unintern temporary. */
        aspath_unintern(&attr.aspath);
 -      aspath_unintern(&attr_ip6.aspath);
        aspath_unintern(&attr_sticky.aspath);
 -      aspath_unintern(&attr_sticky_ip6.aspath);
        aspath_unintern(&attr_def_gw.aspath);
 -      aspath_unintern(&attr_def_gw_ip6.aspath);
 +      aspath_unintern(&attr_ip6_ll.aspath);
  
        return 0;
  }
@@@ -1754,8 -1760,10 +1754,10 @@@ static int delete_routes_for_vni(struc
  }
  
  /*
-  * There is a tunnel endpoint IP address change for this VNI,
-  * need to re-advertise routes with the new nexthop.
+  * There is a tunnel endpoint IP address change for this VNI, delete
+  * prior type-3 route (if needed) and update.
+  * Note: Route re-advertisement happens elsewhere after other processing
+  * other changes.
   */
  static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
                                   struct in_addr originator_ip)
  
        /* Update the tunnel IP and re-advertise all routes for this VNI. */
        vpn->originator_ip = originator_ip;
-       return update_routes_for_vni(bgp, vpn);
+       return 0;
  }
  
  /*
@@@ -1795,7 -1803,6 +1797,7 @@@ static int install_evpn_route_entry_in_
  {
        struct bgp_node *rn;
        struct bgp_info *ri;
 +      struct attr attr;
        struct attr *attr_new;
        int ret = 0;
        struct prefix p;
        } else
                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. */
        for (ri = rn->info; ri; ri = ri->next)
                if (ri->extra
  
        if (!ri) {
                /* 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. */
                ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
                }
                bgp_info_add(rn, ri);
        } else {
 -              if (attrhash_cmp(ri->attr, parent_ri->attr)
 +              if (attrhash_cmp(ri->attr, &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);
 +              attr_new = bgp_attr_intern(&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))
 +              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);
  
                /* Unintern existing, set to new. */
@@@ -3253,15 -3247,25 +3255,25 @@@ void bgp_evpn_withdraw_type5_routes(str
  {
        struct bgp_table *table = NULL;
        struct bgp_node *rn = NULL;
+       struct bgp_info *ri;
  
        /* Bail out early if we don't have to advertise type-5 routes. */
        if (!advertise_type5_routes(bgp_vrf, afi))
                return;
  
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               /* Only care about "selected" routes - non-imported. */
+               /* TODO: Support for AddPath for EVPN. */
+               for (ri = rn->info; ri; ri = ri->next) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+                           (!ri->extra || !ri->extra->parent)) {
+                               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
+                                                             afi, safi);
+                               break;
+                       }
+               }
+       }
  }
  
  /*
@@@ -3282,10 -3286,6 +3294,6 @@@ void bgp_evpn_advertise_type5_route(str
        if (!advertise_type5_routes(bgp_vrf, afi))
                return;
  
-       /* only advertise subnet routes as type-5 */
-       if (is_host_route(p))
-               return;
        build_type5_prefix_from_ip_prefix(&evp, p);
        ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
        if (ret)
@@@ -3313,11 -3313,12 +3321,12 @@@ void bgp_evpn_advertise_type5_routes(st
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
                /* Need to identify the "selected" route entry to use its
-                * attribute.
+                * attribute. Also, we only consider "non-imported" routes.
                 * TODO: Support for AddPath for EVPN.
                 */
                for (ri = rn->info; ri; ri = ri->next) {
-                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+                           (!ri->extra || !ri->extra->parent)) {
  
                                /* apply the route-map */
                                if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
                                        if (ret == RMAP_DENYMATCH)
                                                continue;
                                }
                                bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p,
                                                               ri->attr,
                                                               afi, safi);
@@@ -4457,8 -4457,8 +4465,8 @@@ int bgp_evpn_local_vni_del(struct bgp *
  }
  
  /*
-  * Handle add (or update) of a local VNI. The only VNI change we care
-  * about is change to local-tunnel-ip.
+  * Handle add (or update) of a local VNI. The VNI changes we care
+  * about are for the local-tunnel-ip and the (tenant) VRF.
   */
  int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                           struct in_addr originator_ip,
        vpn = bgp_evpn_lookup_vni(bgp, vni);
        if (vpn) {
  
-               /* update tenant_vrf_id if required */
+               if (is_vni_live(vpn)
+                   && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
+                   && vpn->tenant_vrf_id == tenant_vrf_id)
+                       /* Probably some other param has changed that we don't
+                        * care about. */
+                       return 0;
+               /* Update tenant_vrf_id if it has changed. */
                if (vpn->tenant_vrf_id != tenant_vrf_id) {
                        bgpevpn_unlink_from_l3vni(vpn);
                        vpn->tenant_vrf_id = tenant_vrf_id;
                        bgpevpn_link_to_l3vni(vpn);
-                       /* update all routes with new export RT for VRFs */
-                       update_routes_for_vni(bgp, vpn);
                }
  
-               if (is_vni_live(vpn)
-                   && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
-                       /* Probably some other param has changed that we don't
-                        * care about. */
-                       return 0;
+               /* If tunnel endpoint IP has changed, update (and delete prior
+                * type-3 route, if needed.)
+                */
+               if (!IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
+                       handle_tunnel_ip_change(bgp, vpn, originator_ip);
  
-               /* Local tunnel endpoint IP address has changed */
-               handle_tunnel_ip_change(bgp, vpn, originator_ip);
+               /* Update all routes with new endpoint IP and/or export RT
+                * for VRFs
+                */
+               if (is_vni_live(vpn))
+                       update_routes_for_vni(bgp, vpn);
        }
  
        /* Create or update as appropriate. */
diff --combined lib/ipaddr.h
index e8dbe9cf09d4b6180a36fed0e8859689c7ec98e0,98c28008dc60a36ea6ea76cdf6244a84475ba08e..44bde45add60b25cec307e2d08cd440843840f60
@@@ -85,15 -85,4 +85,21 @@@ static inline char *ipaddr2str(struct i
        }
        return buf;
  }
 +
++/*
++ * Convert IPv4 address to IPv4-mapped IPv6 address which is of the
++ * form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
++ * be used to represent the IPv4 address, wherever only an IPv6 address
++ * is required.
++ */
 +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__ */
diff --combined zebra/zebra_rib.c
index cc4888f3e77f83c3acde7881971e333d4099a066,7f6c8aefa8086626d4e40b31fe3b0b49b6801348..10e5f55e05615ff57d4795e211314fc081b08391
@@@ -305,8 -305,6 +305,8 @@@ struct nexthop *route_entry_nexthop_ipv
        nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
        nexthop->gate.ipv6 = *ipv6;
        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);
  
@@@ -423,10 -421,6 +423,10 @@@ static int nexthop_active(afi_t afi, st
                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 */
        /* The nexthops are specific to this route and so the same */
        /* nexthop for a different route may not have this flag set */
                                        nexthop->ifindex = newhop->ifindex;
                        }
                        return 1;
-               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
+               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
                        resolved = 0;
                        for (ALL_NEXTHOPS(match->nexthop, newhop)) {
                                if (!CHECK_FLAG(newhop->flags,
@@@ -864,7 -858,9 +864,7 @@@ static unsigned nexthop_active_check(st
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                family = AFI_IP;
 -              if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP))
 -                      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 -              else if (nexthop_active(AFI_IP, re, nexthop, set, rn))
 +              if (nexthop_active(AFI_IP, re, nexthop, set, rn))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@@ -2552,17 -2548,10 +2552,17 @@@ void rib_delete(afi_t afi, safi_t safi
                                struct ipaddr vtep_ip;
  
                                memset(&vtep_ip, 0, sizeof(struct ipaddr));
 -                              vtep_ip.ipa_type = IPADDR_V4;
 -                              memcpy(&(vtep_ip.ipaddr_v4),
 -                                     &(tmp_nh->gate.ipv4),
 -                                     sizeof(struct in_addr));
 +                              if (afi == AFI_IP) {
 +                                      vtep_ip.ipa_type = IPADDR_V4;
 +                                      memcpy(&(vtep_ip.ipaddr_v4),
 +                                             &(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,
                                                               &vtep_ip, p);
                        }
diff --combined zebra/zserv.c
index 1fc2bfd309bfa8d541e530a856c2eefd84fefb6e,bca8a509d82ededda2b0db02be3adb82d6ed9174..07258cdb72f0258847a41f53b86fe043cfe76f18
@@@ -1143,7 -1143,6 +1143,7 @@@ static int zread_route_add(struct zser
        struct nexthop *nexthop = NULL;
        int i, ret;
        vrf_id_t vrf_id = 0;
 +      struct ipaddr vtep_ip;
  
        s = client->ibuf;
        if (zapi_route_decode(s, &api) < 0)
                        switch (api_nh->type) {
                        case NEXTHOP_TYPE_IFINDEX:
                                nexthop = route_entry_nexthop_ifindex_add(
-                                       re, api_nh->ifindex, re->vrf_id);
+                                       re, api_nh->ifindex, api_nh->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV4:
                                nexthop = route_entry_nexthop_ipv4_add(
                                        re, &api_nh->gate.ipv4, NULL,
-                                       re->vrf_id);
+                                       api_nh->vrf_id);
                                break;
 -                      case NEXTHOP_TYPE_IPV4_IFINDEX: {
 -
 -                              struct ipaddr vtep_ip;
 +                      case NEXTHOP_TYPE_IPV4_IFINDEX:
  
                                memset(&vtep_ip, 0, sizeof(struct ipaddr));
                                if (CHECK_FLAG(api.flags,
  
                                nexthop = route_entry_nexthop_ipv4_ifindex_add(
                                        re, &api_nh->gate.ipv4, NULL, ifindex,
-                                       re->vrf_id);
+                                       api_nh->vrf_id);
  
                                /* if this an EVPN route entry,
 -                                 program the nh as neigh
 +                               * program the nh as neigh
                                 */
                                if (CHECK_FLAG(api.flags,
                                               ZEBRA_FLAG_EVPN_ROUTE)) {
                                                                &api.prefix);
                                }
                                break;
 -                      }
                        case NEXTHOP_TYPE_IPV6:
                                nexthop = route_entry_nexthop_ipv6_add(
-                                       re, &api_nh->gate.ipv6, re->vrf_id);
+                                       re, &api_nh->gate.ipv6, api_nh->vrf_id);
                                break;
                        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(
 -                                      re, &api_nh->gate.ipv6, api_nh->ifindex,
 +                                      re, &api_nh->gate.ipv6, ifindex,
-                                       re->vrf_id);
+                                       api_nh->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;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                nexthop = route_entry_nexthop_blackhole_add(