attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
/* Add the export RTs for L3VNI - currently only supported for IPV4 host
- * routes */
+ * routes
+ */
if (afi == AFI_IP) {
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
static int update_evpn_type5_route_entry(struct bgp *bgp_def,
struct bgp *bgp_vrf, afi_t afi,
safi_t safi, struct bgp_node *rn,
- struct attr *attr)
+ struct attr *attr, int *route_changed)
{
struct attr *attr_new = NULL;
struct bgp_info *ri = NULL;
struct bgp_info *local_ri = NULL;
struct bgp_info *tmp_ri = NULL;
-
+ *route_changed = 0;
/* locate the local route entry if any */
for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
if (tmp_ri->peer == bgp_def->peer_self
}
/* create a new route entry if one doesnt exist.
- Otherwise see if route attr has changed */
+ Otherwise see if route attr has changed
+ */
if (!local_ri) {
+ /* route has changed as this is the first entry */
+ *route_changed = 1;
+
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr);
tmp_ri = local_ri;
if (!attrhash_cmp(tmp_ri->attr, attr)) {
+
+ /* attribute changed */
+ *route_changed = 1;
+
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr);
struct attr attr;
struct bgp_node *rn = NULL;
struct bgp *bgp_def = NULL;
+ int route_changed = 0;
bgp_def = bgp_get_default();
if (!bgp_def)
/* create or update the route entry within the route node */
update_evpn_type5_route_entry(bgp_def, bgp_vrf,
afi, safi,
- rn, &attr);
+ rn, &attr, &route_changed);
/* schedule for processing and unlock node */
- bgp_process(bgp_def, rn, afi, safi);
- bgp_unlock_node(rn);
+ if (route_changed) {
+ bgp_process(bgp_def, rn, afi, safi);
+ bgp_unlock_node(rn);
+ }
/* uninten temporary */
aspath_unintern(&attr.aspath);
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
bgpevpn_get_rmac(vpn, &attr.rmac);
+ vni2label(vpn->vni, &(attr.label));
/* Set up RT and ENCAP extended community. */
build_evpn_route_extcomm(vpn, &attr,
char buf1[PREFIX_STRLEN];
memset(pp, 0, sizeof(struct prefix));
- ip_prefix_from_type2_prefix(evp, pp);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+ ip_prefix_from_type2_prefix(evp, pp);
+ else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+ ip_prefix_from_type5_prefix(evp, pp);
if (bgp_debug_zebra(NULL)) {
zlog_debug("installing evpn prefix %s as ip prefix %s in vrf %s",
char buf1[PREFIX_STRLEN];
memset(pp, 0, sizeof(struct prefix));
- ip_prefix_from_type2_prefix(evp, pp);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+ ip_prefix_from_type2_prefix(evp, pp);
+ else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+ ip_prefix_from_type5_prefix(evp, pp);
if (bgp_debug_zebra(NULL)) {
zlog_debug("uninstalling evpn prefix %s as ip prefix %s in vrf %s",
struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
/* if not mac-ip route skip this route */
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+ evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
continue;
/* if not a mac+ip route skip this route */
for (ri = rn->info; ri; ri = ri->next) {
/* Consider "valid" remote routes applicable for
- * this VRF. */
+ * this VRF.
+ */
if (!(CHECK_FLAG(ri->flags, BGP_INFO_VALID)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL))
}
/* Install any existing remote routes applicable for this VRF into VRF RIB. This
- * is invoked upon l3vni-add or l3vni import rt change */
+ * is invoked upon l3vni-add or l3vni import rt change
+ */
static int install_routes_for_vrf(struct bgp *bgp_vrf)
{
install_uninstall_routes_for_vrf(bgp_vrf, 1);
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))
+ /* Only type-2/type-5 routes go into a VRF */
+ if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+ evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
return 0;
- /* if not a mac+ip route skip this route */
- if (!(IS_EVPN_PREFIX_IPADDR_V4(evp) ||
- IS_EVPN_PREFIX_IPADDR_V6(evp)))
+ /* if it is type-2 route and not a mac+ip route skip this route */
+ if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ !(IS_EVPN_PREFIX_IPADDR_V4(evp) || IS_EVPN_PREFIX_IPADDR_V6(evp)))
return 0;
for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
assert(attr);
- /* Only type-2 and type-3 routes go into a L2 VNI. */
+ /* Only type-2 and type-3 and type-5 are supported currently */
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
- || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE))
+ || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
+ || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
return 0;
/* If we don't have Route Target, nothing much to do. */
if (!ecom || !ecom->size)
return -1;
- /* For each extended community RT, see which VNIs match and import
- * the route into matching VNIs.
+ /* For each extended community RT, see which VNIs/VRFs match and import
+ * the route into matching VNIs/VRFs.
*/
for (i = 0; i < ecom->size; i++) {
u_char *pnt;
if (sub_type != ECOMMUNITY_ROUTE_TARGET)
continue;
- /* Import route into matching l2-vnis */
+ /* Import route into matching l2-vnis (type-2/type-3 routes go
+ * into l2vni table)
+ */
irt = lookup_import_rt(bgp, eval);
if (irt && irt->vnis)
install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
irt->vnis, import);
- /* Import route into matching l3-vnis (vrfs) */
+ /* Import route into matching l3-vnis (type-2/type-5 routes go
+ * into l3vni/vrf table)
+ */
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
- * and
- * only check on the local-admin sub-field. This is to
- * facilitate using
+ /* Also check for non-exact match. In this,
+ * we mask out the AS and
+ * only check on the local-admin sub-field.
+ * This is to facilitate using
* VNI as the RT for EBGP peering too.
*/
irt = NULL;
/* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn));
p.family = AF_EVPN;
+ p.prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
/* Additional information outside of prefix - ESI and GW IP */
pfx += 4;
memcpy(&evpn.gw_ip.ipv4, pfx, 4);
pfx += 4;
- p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4;
} else {
SET_IPADDR_V6(&p.prefix.ip);
memcpy(&p.prefix.ip.ipaddr_v6, pfx, 16);
pfx += 16;
memcpy(&evpn.gw_ip.ipv6, pfx, 16);
pfx += 16;
- p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
}
label_pnt = (mpls_label_t *)pfx;
return;
p_evpn_p = &(p->u.prefix_evpn);
+ /* len denites the total len of IP and GW-IP in the route
+ IP and GW-IP have to be both ipv4 or ipv6
+ */
if (IS_IPADDR_V4(&p_evpn_p->ip))
- len = 8; /* ipv4 */
+ len = 8; /* IP and GWIP are both ipv4 */
else
- len = 32; /* ipv6 */
+ len = 32; /* IP and GWIP are both ipv6 */
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8);
* Public functions.
*/
+/* withdraw type-5 route corresponding to ip prefix */
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+ afi_t afi, safi_t safi)
+{
+ int ret = 0;
+ struct prefix_evpn evp;
+ char buf[PREFIX_STRLEN];
+
+ build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+ ret = delete_evpn_type5_route(bgp_vrf, &evp);
+ if (ret) {
+ zlog_err(
+ "%u failed to delete type-5 route for prefix %s in vrf %s",
+ bgp_vrf->vrf_id,
+ prefix2str(&rn->p, buf, sizeof(buf)),
+ vrf_id_to_name(bgp_vrf->vrf_id));
+ }
+}
+
/* withdraw all type-5 routes for an address family */
void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
afi_t afi, safi_t safi)
return;
table = bgp_vrf->rib[afi][safi];
- for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+ bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi);
- int ret = 0;
- struct prefix_evpn evp;
- char buf[PREFIX_STRLEN];
+}
- build_type5_prefix_from_ip_prefix(&evp, &rn->p);
- ret = delete_evpn_type5_route(bgp_vrf, &evp);
- if (ret) {
- zlog_err(
- "%u failed to delete type-5 route for prefix %s in vrf %s",
- bgp_vrf->vrf_id,
- prefix2str(&rn->p, buf, sizeof(buf)),
- vrf_id_to_name(bgp_vrf->vrf_id));
- }
+/* advertise ip prefix as type-5 route*/
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+ afi_t afi, safi_t safi)
+{
+ int ret = 0;
+ struct prefix_evpn evp;
+ char buf[PREFIX_STRLEN];
+
+ if (!advertise_type5_routes(bgp_vrf, afi))
+ return;
+
+ if (!rn->info)
+ return;
+
+ /* only advertise subnet routes as type-5 */
+ if (is_host_route(&rn->p))
+ return;
+
+ build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+ ret = update_evpn_type5_route(bgp_vrf, &evp);
+ if (ret) {
+ zlog_err(
+ "%u failed to create type-5 route for prefix %s in vrf %s",
+ bgp_vrf->vrf_id,
+ prefix2str(&rn->p, buf, sizeof(buf)),
+ vrf_id_to_name(bgp_vrf->vrf_id));
}
}
struct bgp_table *table = NULL;
struct bgp_node *rn = NULL;
- 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)) {
-
- int ret = 0;
- struct prefix_evpn evp;
- char buf[PREFIX_STRLEN];
-
- build_type5_prefix_from_ip_prefix(&evp, &rn->p);
- ret = update_evpn_type5_route(bgp_vrf, &evp);
- if (ret) {
- zlog_err(
- "%u failed to create type-5 route for prefix %s in vrf %s",
- bgp_vrf->vrf_id,
- prefix2str(&rn->p, buf, sizeof(buf)),
- vrf_id_to_name(bgp_vrf->vrf_id));
- }
- }
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+ bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
}
void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
list_delete_node(bgp_vrf->vrf_export_rtl, node_to_del);
/* fall back to auto-generated RT if this was the last RT */
- if (list_isempty(bgp_vrf->vrf_export_rtl)) {
+ if (bgp_vrf->vrf_export_rtl && list_isempty(bgp_vrf->vrf_export_rtl)) {
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
}
if (withdraw) {
/* delete and withdraw all the type-5 routes
- stored in the global table for this vrf */
+ stored in the global table for this vrf
+ */
withdraw_router_id_vrf(bgp);
/* delete all the VNI routes (type-2/type-3) routes for all the
- * L2-VNIs */
+ * L2-VNIs
+ */
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *,
void *))withdraw_router_id_vni,
} else {
/* advertise all routes in the vrf as type-5 routes with the new
- * RD */
+ * RD
+ */
update_router_id_vrf(bgp);
/* advertise all the VNI routes (type-2/type-3) routes with the
- * new RD*/
+ * new RD
+ */
hash_iterate(bgp->vnihash,
(void (*)(struct hash_backet *,
void *))update_router_id_vni,
as_t as = 0;
/* get the default instamce - required to get the AS number for VRF
- * auto-creation*/
+ * auto-creatio
+ */
bgp_def = bgp_get_default();
if (!bgp_def) {
zlog_err("Cannot process L3VNI %u ADD - default BGP instance not yet created",
}
/* unimport remote routes from VRF, if it is AUTO vrf bgp_delete will
- * take care of uninstalling the routes from zebra */
+ * take care of uninstalling the routes from zebra
+ */
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
uninstall_routes_for_vrf(bgp_vrf);
bgp->vnihash = NULL;
if (bgp->vrf_import_rtl)
list_delete_and_null(&bgp->vrf_import_rtl);
- bgp->vrf_import_rtl = NULL;
if (bgp->vrf_export_rtl)
list_delete_and_null(&bgp->vrf_export_rtl);
- bgp->vrf_export_rtl = NULL;
if (bgp->l2vnis)
list_delete_and_null(&bgp->l2vnis);
- bgp->l2vnis = NULL;
bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
}