}
/* Flag if the route's parent is a EVPN route. */
-static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+static inline struct bgp_path_info *
+get_route_parent_evpn(struct bgp_path_info *ri)
{
struct bgp_path_info *parent_ri;
- struct bgp_table *table;
- struct bgp_dest *dest;
/* If not imported (or doesn't have a parent), bail. */
if (ri->sub_type != BGP_ROUTE_IMPORTED ||
!ri->extra ||
!ri->extra->parent)
- return 0;
+ return NULL;
/* Determine parent recursively */
for (parent_ri = ri->extra->parent;
parent_ri = parent_ri->extra->parent)
;
+ return parent_ri;
+}
+
+/* Flag if the route's parent is a EVPN route. */
+static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+{
+ struct bgp_path_info *parent_ri;
+ struct bgp_table *table;
+ struct bgp_dest *dest;
+
+ parent_ri = get_route_parent_evpn(ri);
+ if (!parent_ri)
+ return 0;
+
/* See if of family L2VPN/EVPN */
dest = parent_ri->net;
if (!dest)
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mpath.h"
static void bgp_evpn_local_es_down(struct bgp *bgp,
struct bgp_evpn_es *es);
bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
}
+/* returns false if legacy-exploded mp needs to be used for route install */
+bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
+ uint32_t *nhg_p)
+{
+ esi_t *esi;
+ struct bgp_evpn_es *es;
+ struct bgp_evpn_es_vrf *es_vrf;
+ struct bgp_path_info *parent_pi;
+ struct bgp_node *rn;
+ struct prefix_evpn *evp;
+ struct bgp_path_info *mpinfo;
+
+ *nhg_p = 0;
+
+ parent_pi = get_route_parent_evpn(pi);
+ if (!parent_pi)
+ return false;
+
+ rn = parent_pi->net;
+ if (!rn)
+ return false;
+
+ evp = (struct prefix_evpn *)&rn->p;
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return false;
+
+ /* L3NHG support is disabled, use legacy-exploded multipath */
+ if (!bgp_mh_info->host_routes_use_l3nhg)
+ return false;
+
+ /* non-es path, use legacy-exploded multipath */
+ esi = bgp_evpn_attr_get_esi(parent_pi->attr);
+ if (!memcmp(esi, zero_esi, sizeof(*esi)))
+ return false;
+
+ /* if the ES-VRF is not setup or if the NHG has not been installed
+ * we cannot install the route yet, return a 0-NHG to indicate
+ * that
+ */
+ es = bgp_evpn_es_find(esi);
+ if (!es)
+ return true;
+ es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
+ if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+ return true;
+
+ /* this needs to be set the v6NHG if v6route */
+ if (evp->family == AF_INET6)
+ *nhg_p = es_vrf->v6_nhg_id;
+ else
+ *nhg_p = es_vrf->nhg_id;
+
+ for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
+ mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+ /* if any of the paths of have a different ESI we can't use
+ * the NHG associated with the ES. fallback to legacy-exploded
+ * multipath
+ */
+ if (memcmp(esi, bgp_evpn_attr_get_esi(mpinfo->attr),
+ sizeof(*esi)))
+ return false;
+ }
+
+ return true;
+}
+
/*****************************************************************************/
/* Ethernet Segment to EVI association -
* 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
struct listnode es_listnode;
uint32_t nhg_id;
+ uint32_t v6_nhg_id;
/* Number of ES-EVI entries associated with this ES-VRF */
uint32_t ref_cnt;
bool ead_evi_adv_for_down_links;
/* Enable ES consistency checking */
bool consistency_checking;
+ bool host_routes_use_l3nhg;
};
/****************************************************************************/
extern void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni,
esi_t *esi);
extern bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh);
+extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf,
+ struct bgp_path_info *pi, uint32_t *nhg_p);
#endif /* _FRR_BGP_EVPN_MH_H */
int nh_updated;
bool do_wt_ecmp;
uint64_t cum_bw = 0;
+ uint32_t nhg_id = 0;
+ bool is_add;
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
if (do_wt_ecmp)
cum_bw = bgp_path_info_mpath_cumbw(info);
- for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+ /* EVPN MAC-IP routes are installed with a L3 NHG id */
+ if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id))
+ mpinfo = NULL;
+ else
+ mpinfo = info;
+
+ for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
uint32_t nh_weight;
if (valid_nh_count >= multipath_num)
valid_nh_count++;
}
+ is_add = (valid_nh_count || nhg_id) ? true : false;
+
/*
* When we create an aggregate route we must also
* install a Null0 route in the RIB, so overwrite
zlog_debug(
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
- " count %d",
+ " count %d nhg %d",
valid_nh_count ? "add" : "delete", bgp->vrf_id,
- &api.prefix, api.metric, api.tag, api.nexthop_num);
+ &api.prefix, api.metric, api.tag, api.nexthop_num,
+ nhg_id);
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
__func__, buf_prefix,
(recursion_flag ? "" : "NOT "));
}
- zclient_route_send(valid_nh_count ? ZEBRA_ROUTE_ADD
- : ZEBRA_ROUTE_DELETE,
+ zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
zclient, &api);
}
vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
}
-
if (bgp_install_info_to_zebra(bgp)) {
/* Send distribute delete message to zebra. */
if (BGP_DEBUG(zebra, ZEBRA))