summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c858
-rw-r--r--bgpd/bgp_evpn_mh.c4
-rw-r--r--bgpd/bgp_evpn_private.h92
-rw-r--r--bgpd/bgp_evpn_vty.c729
-rw-r--r--bgpd/bgp_evpn_vty.h6
-rw-r--r--bgpd/bgp_route.h5
-rw-r--r--lib/command.h2
-rw-r--r--zebra/zebra_evpn.c58
-rw-r--r--zebra/zebra_evpn_mac.c131
-rw-r--r--zebra/zebra_evpn_mac.h33
-rw-r--r--zebra/zebra_evpn_neigh.c17
-rw-r--r--zebra/zebra_evpn_neigh.h2
12 files changed, 1473 insertions, 464 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index f50a45e94..6d402a4fe 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -66,7 +66,6 @@ DEFINE_QOBJ_TYPE(bgp_evpn_es);
/*
* Static function declarations
*/
-static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn);
static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
@@ -572,12 +571,22 @@ struct bgp_dest *bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi,
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
local_pi) {
/*
- * prefix in the global table needs MAC, ensure it's present,
- * using one from local table's path_info.
+ * prefix in the global table needs MAC/IP, ensure they are
+ * present, using one's from local table's path_info.
*/
- evpn_type2_prefix_global_copy(
- &global_p, evp,
- *evpn_type2_path_info_get_mac(local_pi));
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp,
+ evpn_type2_path_info_get_mac(local_pi),
+ NULL /* ip */);
+ }
+
evp = &global_p;
}
return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd);
@@ -603,23 +612,33 @@ bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
} else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
local_pi) {
/*
- * prefix in the global table needs MAC, ensure it's present,
- * using one from local table's path_info.
+ * prefix in the global table needs MAC/IP, ensure they are
+ * present, using one's from local table's path_info.
*/
- evpn_type2_prefix_global_copy(
- &global_p, evp,
- *evpn_type2_path_info_get_mac(local_pi));
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp,
+ evpn_type2_path_info_get_mac(local_pi),
+ NULL /* ip */);
+ }
+
evp = &global_p;
}
return bgp_afi_node_lookup(table, afi, safi, (struct prefix *)evp, prd);
}
/*
- * Wrapper for node get in VNI table.
+ * Wrapper for node get in VNI IP table.
*/
-struct bgp_dest *bgp_evpn_vni_node_get(struct bgp_table *const table,
- const struct prefix_evpn *evp,
- const struct bgp_path_info *parent_pi)
+struct bgp_dest *bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
{
struct prefix_evpn vni_p;
@@ -627,29 +646,30 @@ struct bgp_dest *bgp_evpn_vni_node_get(struct bgp_table *const table,
/* prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
- evpn_type1_prefix_vni_copy(&vni_p, evp,
- parent_pi->attr->nexthop);
+ evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
+ parent_pi->attr->nexthop);
evp = &vni_p;
- } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
- !is_evpn_prefix_ipaddr_none(evp)) {
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Only MAC-IP should go into this table, not mac-only */
+ assert(is_evpn_prefix_ipaddr_none(evp) == false);
+
/*
- * IP prefix in the vni table doesn't include MAC so
+ * prefix in the vni IP table doesn't include MAC so
* we need to create a different copy of the prefix.
- *
- * However, if it's MAC-only, keep it.
*/
- evpn_type2_prefix_vni_copy(&vni_p, evp);
+ evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
evp = &vni_p;
}
return bgp_node_get(table, (struct prefix *)evp);
}
/*
- * Wrapper for node lookup in VNI table.
+ * Wrapper for node lookup in VNI IP table.
*/
-struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgp_table *const table,
- const struct prefix_evpn *evp,
- const struct bgp_path_info *parent_pi)
+struct bgp_dest *
+bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
{
struct prefix_evpn vni_p;
@@ -657,24 +677,97 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgp_table *const table,
/* prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
- evpn_type1_prefix_vni_copy(&vni_p, evp,
- parent_pi->attr->nexthop);
+ evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
+ parent_pi->attr->nexthop);
evp = &vni_p;
- } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
- !is_evpn_prefix_ipaddr_none(evp)) {
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Only MAC-IP should go into this table, not mac-only */
+ assert(is_evpn_prefix_ipaddr_none(evp) == false);
+
/*
- * IP prefix in the vni table doesn't include MAC so
+ * prefix in the vni IP table doesn't include MAC so
* we need to create a different copy of the prefix.
- *
- * However, if it's MAC-only, keep it.
*/
- evpn_type2_prefix_vni_copy(&vni_p, evp);
+ evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
evp = &vni_p;
}
return bgp_node_lookup(table, (struct prefix *)evp);
}
/*
+ * Wrapper for node get in VNI MAC table.
+ */
+struct bgp_dest *
+bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ /* Only type-2 should ever go into this table */
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+
+ /*
+ * prefix in the vni MAC table doesn't include IP so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
+ evp = &vni_p;
+ return bgp_node_get(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node lookup in VNI MAC table.
+ */
+struct bgp_dest *
+bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ /* Only type-2 should ever go into this table */
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+
+ /*
+ * prefix in the vni MAC table doesn't include IP so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
+ evp = &vni_p;
+ return bgp_node_lookup(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node get in both VNI tables.
+ */
+struct bgp_dest *bgp_evpn_vni_node_get(struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi)
+{
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
+
+ return bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
+}
+
+/*
+ * Wrapper for node lookup in both VNI tables.
+ */
+struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi)
+{
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p,
+ parent_pi);
+
+ return bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
+}
+
+/*
* Add (update) or delete MACIP from zebra.
*/
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
@@ -756,8 +849,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
zlog_debug(
"Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s",
add ? "ADD" : "DEL", vpn->vni,
- &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip,
- flags, seq, &remote_vtep_ip, esi_buf);
+ (mac ? mac : &p->prefix.macip_addr.mac),
+ &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip,
+ esi_buf);
}
frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip,
@@ -1090,7 +1184,11 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
}
ret = bgp_zebra_send_remote_macip(
- bgp, vpn, p, evpn_type2_path_info_get_mac(pi),
+ bgp, vpn, p,
+ (is_evpn_prefix_ipaddr_none(p)
+ ? NULL /* MAC update */
+ : evpn_type2_path_info_get_mac(
+ pi) /* MAC-IP update */),
pi->attr->nexthop, 1, flags, seq,
bgp_evpn_attr_get_esi(pi->attr));
} else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) {
@@ -1124,7 +1222,11 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip(
- bgp, vpn, p, evpn_type2_path_info_get_mac(pi),
+ bgp, vpn, p,
+ (is_evpn_prefix_ipaddr_none(p)
+ ? NULL /* MAC update */
+ : evpn_type2_path_info_get_mac(
+ pi) /* MAC-IP update */),
(is_sync ? zero_vtep_ip : pi->attr->nexthop), 0, 0, 0,
NULL);
else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
@@ -1635,13 +1737,14 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
}
/*
- * Create or update EVPN route entry. This could be in the VNI route table
+ * Create or update EVPN route entry. This could be in the VNI route tables
* or the global route table.
*/
static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
afi_t afi, safi_t safi,
struct bgp_dest *dest, struct attr *attr,
- const struct ethaddr *mac, int add,
+ const struct ethaddr *mac,
+ const struct ipaddr *ip, int add,
struct bgp_path_info **pi, uint8_t flags,
uint32_t seq, bool vpn_rt, bool *old_is_sync)
{
@@ -1716,9 +1819,12 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
memcpy(&tmp_pi->extra->label, label, sizeof(label));
tmp_pi->extra->num_labels = num_labels;
- if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && mac)
- evpn_type2_path_info_set_mac(tmp_pi, *mac);
-
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (mac)
+ evpn_type2_path_info_set_mac(tmp_pi, *mac);
+ else if (ip)
+ evpn_type2_path_info_set_ip(tmp_pi, *ip);
+ }
/* Mark route as self type-2 route */
if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
@@ -1749,9 +1855,14 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
memcpy(&tmp_pi->extra->label, label, sizeof(label));
tmp_pi->extra->num_labels = num_labels;
- if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
- mac)
- evpn_type2_path_info_set_mac(tmp_pi, *mac);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (mac)
+ evpn_type2_path_info_set_mac(tmp_pi,
+ *mac);
+ else if (ip)
+ evpn_type2_path_info_set_ip(tmp_pi,
+ *ip);
+ }
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
@@ -1872,6 +1983,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
safi_t safi = SAFI_EVPN;
int route_change;
bool old_is_sync = false;
+ bool mac_only = false;
memset(&attr, 0, sizeof(attr));
@@ -1931,13 +2043,19 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* 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. */
- dest = bgp_evpn_vni_node_get(vpn->route_table, p, NULL);
+ /* First, create (or fetch) route node within the VNI.
+ * NOTE: There is no RD here.
+ */
+ dest = bgp_evpn_vni_node_get(vpn, p, NULL);
+
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ mac_only = true;
/* Create or update route entry. */
route_change = update_evpn_route_entry(
- bgp, vpn, afi, safi, dest, &attr, &p->prefix.macip_addr.mac, 1,
+ bgp, vpn, afi, safi, dest, &attr,
+ (mac_only ? NULL : &p->prefix.macip_addr.mac), NULL /* ip */, 1,
&pi, flags, seq, true /* setup_sync */, &old_is_sync);
assert(pi);
attr_new = pi->attr;
@@ -1993,10 +2111,10 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
p, &vpn->prd, NULL);
- update_evpn_route_entry(bgp, vpn, afi, safi, dest, attr_new,
- NULL /* mac */, 1, &global_pi, flags,
- seq, false /* setup_sync */,
- NULL /* old_is_sync */);
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, dest, attr_new, NULL /* mac */,
+ NULL /* ip */, 1, &global_pi, flags, seq,
+ false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
bgp_process(bgp, dest, afi, safi);
@@ -2077,9 +2195,9 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* First, locate the route node within the VNI. If it doesn't exist,
* there
* is nothing further to do.
+ * NOTE: There is no RD here.
*/
- /* NOTE: There is no RD here. */
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, NULL);
+ dest = bgp_evpn_vni_node_lookup(vpn, p, NULL);
if (!dest)
return 0;
@@ -2138,8 +2256,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* VNI table MAC-IP prefixes don't have MAC so make sure it's set from
* path info here.
*/
- evpn_type2_prefix_global_copy(&evp, (struct prefix_evpn *)&dest->p,
- *evpn_type2_path_info_get_mac(local_pi));
+ if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->p)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &evp, (struct prefix_evpn *)&dest->p, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &evp, (struct prefix_evpn *)&dest->p,
+ evpn_type2_path_info_get_mac(local_pi), NULL /* ip */);
+ }
/*
* Build attribute per local route as the MAC mobility and
@@ -2186,8 +2313,8 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Update the route entry. */
route_change = update_evpn_route_entry(
- bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, 0, &pi, 0,
- seq, true /* setup_sync */, &old_is_sync);
+ bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, NULL /* ip */,
+ 0, &pi, 0, seq, true /* setup_sync */, &old_is_sync);
assert(pi);
attr_new = pi->attr;
@@ -2235,11 +2362,11 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
global_dest = bgp_evpn_global_node_get(
bgp->rib[afi][safi], afi, safi, &evp, &vpn->prd, NULL);
assert(global_dest);
- update_evpn_route_entry(bgp, vpn, afi, safi, global_dest,
- attr_new, NULL /* mac */, 0, &global_pi,
- 0, mac_mobility_seqnum(attr_new),
- false /* setup_sync */,
- NULL /* old_is_sync */);
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, global_dest, attr_new,
+ NULL /* mac */, NULL /* ip */, 0, &global_pi, 0,
+ mac_mobility_seqnum(attr_new), false /* setup_sync */,
+ NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
bgp_process(bgp, global_dest, afi, safi);
@@ -2250,43 +2377,51 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
aspath_unintern(&attr.aspath);
}
+static void update_type2_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest)
+{
+ struct bgp_path_info *tmp_pi;
+
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return;
+
+ /* Identify local route. */
+ for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
+ tmp_pi = tmp_pi->next) {
+ if (tmp_pi->peer == bgp->peer_self &&
+ tmp_pi->type == ZEBRA_ROUTE_BGP &&
+ tmp_pi->sub_type == BGP_ROUTE_STATIC)
+ break;
+ }
+
+ if (!tmp_pi)
+ return;
+
+ bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi, __func__);
+}
+
/*
* Update all type-2 (MACIP) local routes for this VNI - these should also
* be scheduled for advertise to peers.
*/
-static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct bgp_dest *dest;
- struct bgp_path_info *tmp_pi;
- /* Walk this VNI's route table and update local type-2 routes. For any
- * routes updated, update corresponding entry in the global table too.
+ /* Walk this VNI's route MAC & IP table and update local type-2
+ * routes. For any routes updated, update corresponding entry in the
+ * global table too.
*/
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
- continue;
-
- /* Identify local route. */
- for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
- tmp_pi = tmp_pi->next) {
- if (tmp_pi->peer == bgp->peer_self
- && tmp_pi->type == ZEBRA_ROUTE_BGP
- && tmp_pi->sub_type == BGP_ROUTE_STATIC)
- break;
- }
-
- if (!tmp_pi)
- continue;
-
- bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi,
- __func__);
- }
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ update_type2_route(bgp, vpn, dest);
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ update_type2_route(bgp, vpn, dest);
}
/*
@@ -2327,55 +2462,65 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
}
}
+static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest)
+{
+ struct bgp_path_info *pi;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return;
+
+ delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
+
+ /* Route entry in local table gets deleted immediately. */
+ if (pi)
+ bgp_path_info_reap(dest, pi);
+}
+
+static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ struct bgp_dest *dest;
+
+ /* Next, walk this VNI's MAC & IP route table and delete local type-2
+ * routes.
+ */
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ delete_vni_type2_route(bgp, dest);
+
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ delete_vni_type2_route(bgp, dest);
+}
+
/*
* Delete all type-2 (MACIP) local routes for this VNI - from the global
* table as well as the per-VNI route table.
*/
-static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
- afi_t afi;
- safi_t safi;
- struct bgp_dest *dest;
- struct bgp_path_info *pi;
-
- afi = AFI_L2VPN;
- safi = SAFI_EVPN;
-
/* First, walk the global route table for this VNI's type-2 local
* routes.
* EVPN routes are a 2-level table, first get the RD table.
*/
delete_global_type2_routes(bgp, vpn);
-
- /* Next, walk this VNI's route table and delete local type-2 routes. */
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
- continue;
-
- delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
-
- /* Route entry in local table gets deleted immediately. */
- if (pi)
- bgp_path_info_reap(dest, pi);
- }
-
- return 0;
+ delete_vni_type2_routes(bgp, vpn);
}
/*
* Delete all routes in the per-VNI route table.
*/
-static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct bgp_dest *dest;
struct bgp_path_info *pi, *nextpi;
- /* Walk this VNI's route table and delete all routes. */
- for (dest = bgp_table_top(vpn->route_table); dest;
+ /* Walk this VNI's MAC & IP route table and delete all routes. */
+ for (dest = bgp_table_top(vpn->mac_table); dest;
dest = bgp_route_next(dest)) {
for (pi = bgp_dest_get_bgp_path_info(dest);
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
@@ -2385,7 +2530,14 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
}
}
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest)) {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
+ bgp_path_info_delete(dest, pi);
+ bgp_path_info_reap(dest, pi);
+ }
+ }
}
/* BUM traffic flood mode per-l2-vni */
@@ -2432,7 +2584,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return ret;
}
- return update_all_type2_routes(bgp, vpn);
+ update_all_type2_routes(bgp, vpn);
+ return 0;
}
/*
@@ -2449,9 +2602,7 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
/* Delete and withdraw locally learnt type-2 routes (MACIP)
* followed by type-3 routes (only one) - for this VNI.
*/
- ret = delete_all_type2_routes(bgp, vpn);
- if (ret)
- return ret;
+ delete_all_type2_routes(bgp, vpn);
build_evpn_type3_prefix(&p, vpn->originator_ip);
ret = delete_evpn_route(bgp, vpn, &p);
@@ -2459,7 +2610,8 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return ret;
/* Delete all routes from the per-VNI table. */
- return delete_all_vni_routes(bgp, vpn);
+ delete_all_vni_routes(bgp, vpn);
+ return 0;
}
/*
@@ -2719,13 +2871,12 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/*
- * Install route entry into the VNI routing table and invoke route selection.
+ * Common handling for vni route tables install/selection.
*/
-static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- struct bgp_path_info *parent_pi)
+static int install_evpn_route_entry_in_vni_common(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ struct bgp_dest *dest, struct bgp_path_info *parent_pi)
{
- struct bgp_dest *dest;
struct bgp_path_info *pi;
struct bgp_path_info *local_pi;
struct attr *attr_new;
@@ -2733,10 +2884,6 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
bool old_local_es = false;
bool new_local_es;
- /* Create (or fetch) route within the VNI. */
- /* NOTE: There is no RD here. */
- dest = bgp_evpn_vni_node_get(vpn->route_table, p, parent_pi);
-
/* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->extra
@@ -2748,9 +2895,14 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
pi = bgp_create_evpn_bgp_path_info(parent_pi, dest,
parent_pi->attr);
- if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
- evpn_type2_path_info_set_mac(pi,
- p->prefix.macip_addr.mac);
+ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (is_evpn_type2_dest_ipaddr_none(dest))
+ evpn_type2_path_info_set_ip(
+ pi, p->prefix.macip_addr.ip);
+ else
+ evpn_type2_path_info_set_mac(
+ pi, p->prefix.macip_addr.mac);
+ }
new_local_es = bgp_evpn_attr_is_local_es(pi->attr);
} else {
@@ -2809,12 +2961,160 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
if (local_pi && (old_local_es || new_local_es))
bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
__func__);
+
+ return ret;
+}
+
+/*
+ * Common handling for vni route tables uninstall/selection.
+ */
+static int uninstall_evpn_route_entry_in_vni_common(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ struct bgp_dest *dest, struct bgp_path_info *parent_pi)
+{
+ struct bgp_path_info *pi;
+ struct bgp_path_info *local_pi;
+ int ret;
+
+ /* Find matching route entry. */
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ if (pi->extra &&
+ (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ break;
+
+ if (!pi)
+ return 0;
+
+ bgp_evpn_remote_ip_hash_del(vpn, pi);
+
+ /* Mark entry for deletion */
+ bgp_path_info_delete(dest, pi);
+
+ /* Perform route selection and update zebra, if required. */
+ ret = evpn_route_select_install(bgp, vpn, dest);
+
+ /* if the best path is a local path with a non-zero ES
+ * sync info against the local path may need to be updated
+ * when a remote path is deleted
+ */
+ local_pi = bgp_evpn_route_get_local_path(bgp, dest);
+ if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr))
+ bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
+ __func__);
+
+ return ret;
+}
+
+/*
+ * Install route entry into VNI IP table and invoke route selection.
+ */
+static int install_evpn_route_entry_in_vni_ip(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Ignore MAC Only Type-2 */
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return 0;
+
+ /* Create (or fetch) route within the VNI IP table. */
+ dest = bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
+
+ ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+
+/*
+ * Install route entry into VNI MAC table and invoke route selection.
+ */
+static int install_evpn_route_entry_in_vni_mac(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Only type-2 routes go into this table */
+ if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return 0;
+
+ /* Create (or fetch) route within the VNI MAC table. */
+ dest = bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
+
+ ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+
+/*
+ * Uninstall route entry from VNI IP table and invoke route selection.
+ */
+static int uninstall_evpn_route_entry_in_vni_ip(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Ignore MAC Only Type-2 */
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return 0;
+
+ /* Locate route within the VNI IP table. */
+ dest = bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
+ if (!dest)
+ return 0;
+
+ ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
bgp_dest_unlock_node(dest);
return ret;
}
/*
+ * Uninstall route entry from VNI IP table and invoke route selection.
+ */
+static int
+uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Only type-2 routes go into this table */
+ if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return 0;
+
+ /* Locate route within the VNI MAC table. */
+ dest = bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p, parent_pi);
+ if (!dest)
+ return 0;
+
+ ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+/*
* Uninstall route entry from the VRF routing table and send message
* to zebra, if appropriate.
*/
@@ -2892,54 +3192,79 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/*
- * Uninstall route entry from the VNI routing table and send message
- * to zebra, if appropriate.
+ * Install route entry into the VNI routing tables.
+ */
+static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret = 0;
+
+ if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s (%u): Installing EVPN %pFX route in VNI %u IP/MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ ret = install_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
+
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to install EVPN %pFX route in VNI %u MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ return ret;
+ }
+
+ ret = install_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
+
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to install EVPN %pFX route in VNI %u IP table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * Uninstall route entry from the VNI routing tables.
*/
static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
- struct bgp_dest *dest;
- struct bgp_path_info *pi;
- struct bgp_path_info *local_pi;
- int ret;
-
- /* Locate route within the VNI. */
- /* NOTE: There is no RD here. */
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, parent_pi);
- if (!dest)
- return 0;
+ int ret = 0;
- /* Find matching route entry. */
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra
- && (struct bgp_path_info *)pi->extra->parent == parent_pi)
- break;
+ if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s (%u): Uninstalling EVPN %pFX route from VNI %u IP/MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- if (!pi) {
- bgp_dest_unlock_node(dest);
- return 0;
- }
+ ret = uninstall_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
- bgp_evpn_remote_ip_hash_del(vpn, pi);
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u IP table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- /* Mark entry for deletion */
- bgp_path_info_delete(dest, pi);
+ return ret;
+ }
- /* Perform route selection and update zebra, if required. */
- ret = evpn_route_select_install(bgp, vpn, dest);
+ ret = uninstall_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
- /* if the best path is a local path with a non-zero ES
- * sync info against the local path may need to be updated
- * when a remote path is deleted
- */
- local_pi = bgp_evpn_route_get_local_path(bgp, dest);
- if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr))
- bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
- __func__);
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- /* Unlock route node. */
- bgp_dest_unlock_node(dest);
+ return ret;
+ }
return ret;
}
@@ -3515,7 +3840,8 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
* we need to create a different copy for the VNI
*/
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
- evp = evpn_type1_prefix_vni_copy(&ad_evp, evp, attr->nexthop);
+ evp = evpn_type1_prefix_vni_ip_copy(&ad_evp, evp,
+ attr->nexthop);
ecom = bgp_attr_get_ecommunity(attr);
if (!ecom || !ecom->size)
@@ -3730,16 +4056,94 @@ static void withdraw_router_id_vrf(struct bgp *bgp_vrf)
delete_withdraw_vrf_routes(bgp_vrf);
}
+static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest)
+{
+ struct bgp_dest *global_dest;
+ struct bgp_path_info *pi, *global_pi;
+ struct attr *attr;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+
+ struct prefix_evpn tmp_evp;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ /*
+ * We have already processed type-3 routes.
+ * Process only type-1 and type-2 routes here.
+ */
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
+ return;
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP &&
+ pi->sub_type == BGP_ROUTE_STATIC)
+ break;
+ if (!pi)
+ return;
+
+ /*
+ * VNI table MAC-IP prefixes don't have MAC so make sure it's
+ * set from path info here.
+ */
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &tmp_evp, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &tmp_evp, evp, evpn_type2_path_info_get_mac(pi),
+ NULL /* ip */);
+ }
+ } else {
+ memcpy(&tmp_evp, evp, sizeof(tmp_evp));
+ }
+
+ /* Create route in global routing table using this route entry's
+ * attribute.
+ */
+ attr = pi->attr;
+ global_dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ &tmp_evp, &vpn->prd, NULL);
+ assert(global_dest);
+
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Type-2 route */
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
+ NULL /* ip */, 1, &global_pi, 0,
+ mac_mobility_seqnum(attr), false /* setup_sync */,
+ NULL /* old_is_sync */);
+ } else {
+ /* Type-1 route */
+ struct bgp_evpn_es *es;
+ int route_changed = 0;
+
+ es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi);
+ bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, global_dest,
+ attr, &global_pi, &route_changed);
+ }
+
+ /* Schedule for processing and unlock node. */
+ bgp_process(bgp, global_dest, afi, safi);
+ bgp_dest_unlock_node(global_dest);
+}
+
/*
* Update and advertise local routes for a VNI. Invoked upon router-id
* change. Note that the processing is done only on the global route table
* using routes that already exist in the per-VNI table.
*/
-static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct prefix_evpn p;
struct bgp_dest *dest, *global_dest;
- struct bgp_path_info *pi, *global_pi;
+ struct bgp_path_info *pi;
struct attr *attr;
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
@@ -3753,9 +4157,9 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
== VXLAN_FLOOD_HEAD_END_REPL) {
build_evpn_type3_prefix(&p, vpn->originator_ip);
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest) /* unexpected */
- return 0;
+ return;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == bgp->peer_self &&
pi->type == ZEBRA_ROUTE_BGP
@@ -3763,15 +4167,16 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
break;
if (!pi) {
bgp_dest_unlock_node(dest);
- return 0;
+ return;
}
+
attr = pi->attr;
global_dest = bgp_evpn_global_node_get(
bgp->rib[afi][safi], afi, safi, &p, &vpn->prd, NULL);
update_evpn_route_entry(
bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
- 1, &pi, 0, mac_mobility_seqnum(attr),
+ NULL /* ip */, 1, &pi, 0, mac_mobility_seqnum(attr),
false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
@@ -3779,71 +4184,16 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
bgp_dest_unlock_node(global_dest);
}
- /* Now, walk this VNI's route table and use the route and its attribute
- * to create and schedule route in global table.
+ /* Now, walk this VNI's MAC & IP route table and use the route and its
+ * attribute to create and schedule route in global table.
*/
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- struct prefix_evpn tmp_evp;
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- /*
- * We have already processed type-3 routes.
- * Process only type-1 and type-2 routes here.
- */
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
- && evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
- continue;
-
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->peer == bgp->peer_self
- && pi->type == ZEBRA_ROUTE_BGP
- && pi->sub_type == BGP_ROUTE_STATIC)
- break;
- if (!pi)
- continue;
-
- /*
- * VNI table MAC-IP prefixes don't have MAC so make sure it's
- * set from path info here.
- */
- evpn_type2_prefix_global_copy(
- &tmp_evp, evp, *evpn_type2_path_info_get_mac(pi));
-
- /* Create route in global routing table using this route entry's
- * attribute.
- */
- attr = pi->attr;
- global_dest =
- bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
- &tmp_evp, &vpn->prd, NULL);
- assert(global_dest);
-
- if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
- /* Type-2 route */
- update_evpn_route_entry(
- bgp, vpn, afi, safi, global_dest, attr,
- NULL /* mac */, 1, &global_pi, 0,
- mac_mobility_seqnum(attr),
- false /* setup_sync */, NULL /* old_is_sync */);
- } else {
- /* Type-1 route */
- struct bgp_evpn_es *es;
- int route_changed = 0;
-
- es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi);
- bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi,
- global_dest, attr, &global_pi,
- &route_changed);
- }
-
- /* Schedule for processing and unlock node. */
- bgp_process(bgp, global_dest, afi, safi);
- bgp_dest_unlock_node(global_dest);
- }
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ update_advertise_vni_route(bgp, vpn, dest);
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ update_advertise_vni_route(bgp, vpn, dest);
}
/*
@@ -5468,8 +5818,9 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
bf_assign_index(bm->rd_idspace, vpn->rd_id);
derive_rd_rt_for_vni(bgp, vpn);
- /* Initialize EVPN route table. */
- vpn->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
+ /* Initialize EVPN route tables. */
+ vpn->ip_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
+ vpn->mac_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
/* Add to hash */
(void)hash_get(bgp->vnihash, vpn, hash_alloc_intern);
@@ -5497,7 +5848,8 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
bgp_evpn_remote_ip_hash_destroy(vpn);
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
- bgp_table_unlock(vpn->route_table);
+ bgp_table_unlock(vpn->ip_table);
+ bgp_table_unlock(vpn->mac_table);
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
list_delete(&vpn->import_rtl);
list_delete(&vpn->export_rtl);
@@ -5623,7 +5975,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
delete_evpn_route(bgp, vpn, &p);
} else {
/* Re-instate the current remote best path if any */
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (dest) {
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
bgp_dest_unlock_node(dest);
@@ -6629,7 +6981,7 @@ void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
bgp_evpn_remote_ip_hash_init(vpn);
- for (dest = bgp_table_top(vpn->route_table); dest;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
dest = bgp_route_next(dest))
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
bgp_evpn_remote_ip_hash_add(vpn, pi);
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index a0ab0881e..2a5c5d7ec 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -471,7 +471,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
struct prefix_rd *prd;
if (vpn) {
- rt_table = vpn->route_table;
+ rt_table = vpn->ip_table;
prd = &vpn->prd;
} else {
rt_table = es->route_table;
@@ -960,7 +960,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
/* First, create (or fetch) route node within the VNI. */
- dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
+ dest = bgp_node_get(vpn->ip_table, (struct prefix *)p);
/* Create or update route entry. */
ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 9b4405afe..eb78a755d 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -112,9 +112,10 @@ struct bgpevpn {
*/
struct hash *remote_ip_hash;
- /* Route table for EVPN routes for
+ /* Route tables for EVPN routes for
* this VNI. */
- struct bgp_table *route_table;
+ struct bgp_table *ip_table;
+ struct bgp_table *mac_table;
/* RB tree of ES-EVIs */
struct bgp_es_evi_rb_head es_evi_rb_tree;
@@ -531,10 +532,10 @@ static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p,
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
-static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
- struct prefix_evpn *vni_p,
- const struct prefix_evpn *global_p,
- struct in_addr originator_ip)
+static inline struct prefix_evpn *
+evpn_type1_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p,
+ struct in_addr originator_ip)
{
memcpy(vni_p, global_p, sizeof(*vni_p));
vni_p->prefix.ead_addr.ip.ipa_type = IPADDR_V4;
@@ -543,29 +544,49 @@ static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
return vni_p;
}
-static inline void
-evpn_type2_prefix_global_copy(struct prefix_evpn *global_p,
- const struct prefix_evpn *vni_p,
- const struct ethaddr mac)
+static inline void evpn_type2_prefix_global_copy(
+ struct prefix_evpn *global_p, const struct prefix_evpn *vni_p,
+ const struct ethaddr *mac, const struct ipaddr *ip)
{
memcpy(global_p, vni_p, sizeof(*global_p));
- global_p->prefix.macip_addr.mac = mac;
+
+ if (mac)
+ global_p->prefix.macip_addr.mac = *mac;
+
+ if (ip)
+ global_p->prefix.macip_addr.ip = *ip;
}
static inline void
-evpn_type2_prefix_vni_copy(struct prefix_evpn *vni_p,
- const struct prefix_evpn *global_p)
+evpn_type2_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p)
{
memcpy(vni_p, global_p, sizeof(*vni_p));
memset(&vni_p->prefix.macip_addr.mac, 0, sizeof(struct ethaddr));
}
+static inline void
+evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p)
+{
+ memcpy(vni_p, global_p, sizeof(*vni_p));
+ memset(&vni_p->prefix.macip_addr.ip, 0, sizeof(struct ipaddr));
+}
+
/* Get MAC of path_info prefix */
static inline struct ethaddr *
evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi)
{
assert(local_pi->extra);
- return &local_pi->extra->mac;
+ return &local_pi->extra->vni_info.mac;
+}
+
+/* Get IP of path_info prefix */
+static inline struct ipaddr *
+evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi)
+{
+ assert(local_pi->extra);
+ return &local_pi->extra->vni_info.ip;
}
/* Set MAC of path_info prefix */
@@ -573,7 +594,25 @@ static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi,
const struct ethaddr mac)
{
assert(local_pi->extra);
- local_pi->extra->mac = mac;
+ local_pi->extra->vni_info.mac = mac;
+}
+
+/* Set IP of path_info prefix */
+static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi,
+ const struct ipaddr ip)
+{
+ assert(local_pi->extra);
+ local_pi->extra->vni_info.ip = ip;
+}
+
+/* Is the IP empty for the RT's dest? */
+static inline bool is_evpn_type2_dest_ipaddr_none(const struct bgp_dest *dest)
+{
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+ return is_evpn_prefix_ipaddr_none(evp);
}
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
@@ -676,13 +715,28 @@ bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
struct prefix_rd *prd,
const struct bgp_path_info *local_pi);
extern struct bgp_dest *
-bgp_evpn_vni_node_get(struct bgp_table *const table,
- const struct prefix_evpn *evp,
+bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_node_get(struct bgpevpn *vpn, const struct prefix_evpn *p,
const struct bgp_path_info *parent_pi);
extern struct bgp_dest *
-bgp_evpn_vni_node_lookup(const struct bgp_table *const table,
- const struct prefix_evpn *evp,
+bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p,
const struct bgp_path_info *parent_pi);
+
extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp,
struct bgpevpn *vpn,
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index fc2271ed7..f8110117e 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -57,6 +57,8 @@ struct vni_walk_ctx {
struct in_addr vtep_ip;
json_object *json;
int detail;
+ int type;
+ bool mac_table;
};
int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
@@ -771,9 +773,10 @@ static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
}
-static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
- struct vty *vty, struct in_addr vtep_ip,
- json_object *json, int detail)
+static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn,
+ struct vty *vty, int type, bool mac_table,
+ struct in_addr vtep_ip, json_object *json,
+ int detail)
{
struct bgp_dest *dest;
struct bgp_path_info *pi;
@@ -784,7 +787,11 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
prefix_cnt = path_cnt = 0;
- table = vpn->route_table;
+ if (mac_table)
+ table = vpn->mac_table;
+ else
+ table = vpn->ip_table;
+
tbl_ver = table->version;
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
const struct prefix_evpn *evp =
@@ -829,14 +836,26 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
/*
- * VNI table MAC-IP prefixes don't have MAC so
- * make sure it's set from path info
- * here.
+ * VNI IP/MAC table prefixes don't have MAC/IP
+ * respectively so make sure it's set from path
+ * info here.
*/
- evpn_type2_prefix_global_copy(
- (struct prefix_evpn *)&tmp_p,
- (struct prefix_evpn *)p,
- *evpn_type2_path_info_get_mac(pi));
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p,
+ evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(
+ pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p,
+ evp,
+ evpn_type2_path_info_get_mac(
+ pi),
+ NULL /* ip */);
+ }
} else
memcpy(&tmp_p, p, sizeof(tmp_p));
@@ -849,6 +868,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
AFI_L2VPN, SAFI_EVPN,
RPKI_NOT_BEING_USED,
json_path);
+
else
route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN,
json_path, false);
@@ -862,19 +882,6 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
if (json) {
if (add_prefix_to_json) {
- struct prefix tmp_p;
-
- if (evp->prefix.route_type ==
- BGP_EVPN_MAC_IP_ROUTE) {
- pi = bgp_dest_get_bgp_path_info(dest);
- evpn_type2_prefix_global_copy(
- (struct prefix_evpn *)&tmp_p,
- (struct prefix_evpn *)p,
- *evpn_type2_path_info_get_mac(
- pi));
- } else
- memcpy(&tmp_p, p, sizeof(tmp_p));
-
json_object_string_addf(json_prefix, "prefix",
"%pFX", p);
json_object_int_add(json_prefix, "prefixLen",
@@ -924,11 +931,47 @@ static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg)
vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
}
- show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni,
- wctx->detail);
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, wctx->type, wctx->mac_table,
+ wctx->vtep_ip, json_vni, wctx->detail);
+
+ if (json)
+ json_object_object_add(json, vni_str, json_vni);
+}
+
+static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg)
+{
+ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+ struct vni_walk_ctx *wctx = arg;
+ struct vty *vty = wctx->vty;
+ json_object *json = wctx->json;
+ json_object *json_vni = NULL;
+ json_object *json_vni_mac = NULL;
+ char vni_str[VNI_STR_LEN];
+
+ snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni);
+ if (json) {
+ json_vni = json_object_new_object();
+ json_object_int_add(json_vni, "vni", vpn->vni);
+ } else {
+ vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
+ }
+
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, false, wctx->vtep_ip,
+ json_vni, wctx->detail);
if (json)
json_object_object_add(json, vni_str, json_vni);
+
+ if (json)
+ json_vni_mac = json_object_new_object();
+ else
+ vty_out(vty, "\nVNI: %d MAC Table\n\n", vpn->vni);
+
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, true, wctx->vtep_ip,
+ json_vni_mac, wctx->detail);
+
+ if (json)
+ json_object_object_add(json_vni, "macTable", json_vni_mac);
}
static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
@@ -2351,9 +2394,9 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
/*
* Display EVPN routes for all VNIs - vty handler.
*/
-static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
- struct in_addr vtep_ip, json_object *json,
- int detail)
+static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, int type,
+ bool mac_table, struct in_addr vtep_ip,
+ json_object *json, int detail)
{
uint32_t num_vnis;
struct vni_walk_ctx wctx;
@@ -2364,6 +2407,8 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
memset(&wctx, 0, sizeof(wctx));
wctx.bgp = bgp;
wctx.vty = vty;
+ wctx.type = type;
+ wctx.mac_table = mac_table;
wctx.vtep_ip = vtep_ip;
wctx.json = json;
wctx.detail = detail;
@@ -2373,6 +2418,32 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
}
/*
+ * Display EVPN routes for all VNIs & all types - vty handler.
+ */
+static void evpn_show_routes_vni_all_type_all(struct vty *vty, struct bgp *bgp,
+ struct in_addr vtep_ip,
+ json_object *json, int detail)
+{
+ uint32_t num_vnis;
+ struct vni_walk_ctx wctx;
+
+ num_vnis = hashcount(bgp->vnihash);
+ if (!num_vnis)
+ return;
+
+ memset(&wctx, 0, sizeof(struct vni_walk_ctx));
+ wctx.bgp = bgp;
+ wctx.vty = vty;
+ wctx.vtep_ip = vtep_ip;
+ wctx.json = json;
+ wctx.detail = detail;
+ hash_iterate(bgp->vnihash,
+ (void (*)(struct hash_bucket *,
+ void *))show_vni_routes_all_hash,
+ &wctx);
+}
+
+/*
* Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
*/
static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
@@ -2400,7 +2471,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
/* See if route exists. */
build_evpn_type3_prefix(&p, orig_ip);
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
if (!json)
vty_out(vty, "%% Network not in table\n");
@@ -2465,6 +2536,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
afi_t afi;
safi_t safi;
json_object *json_paths = NULL;
+ struct ethaddr empty_mac = {};
+ const struct prefix_evpn *evp;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
@@ -2477,9 +2550,10 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
return;
}
+ build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip);
+
/* See if route exists. Look for both non-sticky and sticky. */
- build_evpn_type2_prefix(&p, mac, ip);
- dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
if (!json)
vty_out(vty, "%% Network not in table\n");
@@ -2494,16 +2568,18 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
* MAC is per-path, we have to walk the path_info's and look for it
* first here.
*/
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
- if (memcmp(mac, evpn_type2_path_info_get_mac(pi),
- sizeof(*mac)) == 0)
- break;
- }
+ if (ip && mac) {
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+ if (memcmp(mac, evpn_type2_path_info_get_mac(pi),
+ sizeof(*mac)) == 0)
+ break;
+ }
- if (!pi) {
- if (!json)
- vty_out(vty, "%% Network not in table\n");
- return;
+ if (!pi) {
+ if (!json)
+ vty_out(vty, "%% Network not in table\n");
+ return;
+ }
}
if (json)
@@ -2513,12 +2589,15 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
afi, safi, json);
+ evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
/* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
json_object *json_path = NULL;
/* skip non-matching MACs */
- if (memcmp(mac, evpn_type2_path_info_get_mac(pi),
+ if (ip && mac &&
+ memcmp(mac, evpn_type2_path_info_get_mac(pi),
sizeof(*mac)) != 0)
continue;
@@ -2530,10 +2609,19 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
* make sure it's set from path info
* here.
*/
- evpn_type2_prefix_global_copy(
- (struct prefix_evpn *)&tmp_p,
- (struct prefix_evpn *)bgp_dest_get_prefix(dest),
- *evpn_type2_path_info_get_mac(pi));
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p, evp,
+ NULL /* mac */,
+ evpn_type2_path_info_get_ip(pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p, evp,
+ evpn_type2_path_info_get_mac(pi),
+ NULL /* ip */);
+ }
route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p,
pi, afi, safi, RPKI_NOT_BEING_USED,
@@ -2581,8 +2669,8 @@ static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp,
* If the vtep_ip is non zero, only routes behind that vtep are shown
*/
static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
- int type, struct in_addr vtep_ip,
- json_object *json)
+ int type, bool mac_table,
+ struct in_addr vtep_ip, json_object *json)
{
struct bgpevpn *vpn;
@@ -2595,7 +2683,7 @@ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
}
/* Walk this VNI's route table and display appropriate routes. */
- show_vni_routes(bgp, vpn, type, vty, vtep_ip, json, 0);
+ show_vni_routes(bgp, vpn, vty, type, mac_table, vtep_ip, json, 0);
}
/*
@@ -4633,28 +4721,32 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
as_type, as, show_flags);
}
+static int bgp_evpn_cli_parse_type_cmp(int *type, const char *type_str)
+{
+ if ((strncmp(type_str, "ma", 2) == 0) || (strmatch(type_str, "2")))
+ *type = BGP_EVPN_MAC_IP_ROUTE;
+ else if ((strncmp(type_str, "mu", 2) == 0) || (strmatch(type_str, "3")))
+ *type = BGP_EVPN_IMET_ROUTE;
+ else if ((strncmp(type_str, "es", 2) == 0) || (strmatch(type_str, "4")))
+ *type = BGP_EVPN_ES_ROUTE;
+ else if ((strncmp(type_str, "ea", 2) == 0) || (strmatch(type_str, "1")))
+ *type = BGP_EVPN_AD_ROUTE;
+ else if ((strncmp(type_str, "p", 1) == 0) || (strmatch(type_str, "5")))
+ *type = BGP_EVPN_IP_PREFIX_ROUTE;
+ else
+ return -1;
+
+ return 0;
+}
+
int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc)
{
int type_idx = 0;
if (argv_find(argv, argc, "type", &type_idx)) {
/* Specific type is requested */
- if ((strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "2")))
- *type = BGP_EVPN_MAC_IP_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "3")))
- *type = BGP_EVPN_IMET_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "4")))
- *type = BGP_EVPN_ES_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "ea", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "1")))
- *type = BGP_EVPN_AD_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "p", 1) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "5")))
- *type = BGP_EVPN_IP_PREFIX_ROUTE;
- else
+ if (bgp_evpn_cli_parse_type_cmp(type,
+ argv[type_idx + 1]->arg) != 0)
return -1;
}
@@ -4952,7 +5044,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
}
}
- evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
+ evpn_show_routes_vni(vty, bgp, vni, type, false, vtep_ip, json);
if (uj)
vty_json(vty, json);
@@ -5134,10 +5226,497 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
}
}
- evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da);
+ evpn_show_routes_vni_all(vty, bgp, 0, false, vtep_ip, json, da);
- if (uj)
+ if (uj) {
vty_json(vty, json);
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN ALL routing tables - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all,
+ show_bgp_vni_all_cmd,
+ "show bgp vni all [vtep A.B.C.D$addr] [detail$detail]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ /*
+ if (uj)
+ json = json_object_new_object();
+ */
+
+ evpn_show_routes_vni_all_type_all(vty, bgp, addr, json, !!detail);
+
+ /*
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+ */
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN EAD routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_ead,
+ show_bgp_vni_all_ead_cmd,
+ "show bgp vni all type <1|ead> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_AD_ROUTE, false, addr, json,
+ !!detail);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_macip_mac,
+ show_bgp_vni_all_macip_mac_cmd,
+ "show bgp vni all type <2|macip> mac [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, true, addr,
+ json, !!detail);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN IP routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_macip_ip,
+ show_bgp_vni_all_macip_ip_cmd,
+ "show bgp vni all type <2|macip> ip [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "IP Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, false, addr,
+ json, !!detail);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN Multicast routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_imet,
+ show_bgp_vni_all_imet_cmd,
+ "show bgp vni all type <3|multicast> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_IMET_ROUTE, false, addr,
+ json, !!detail);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN ALL routing tables - for select VNI
+ */
+DEFPY(show_bgp_vni,
+ show_bgp_vni_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR)
+{
+ struct bgp *bgp;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ evpn_show_routes_vni(vty, bgp, vni, 0, false, addr, NULL);
+ vty_out(vty, "\n\nMAC Table:\n\n");
+ evpn_show_routes_vni(vty, bgp, vni, 0, true, addr, NULL);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN EAD routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_ead,
+ show_bgp_vni_ead_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <1|ead> [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_AD_ROUTE, false, addr,
+ json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC-IP MAC routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_macip_mac,
+ show_bgp_vni_macip_mac_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, true, addr,
+ json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC-IP IP routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_macip_ip,
+ show_bgp_vni_macip_ip_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> ip [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "IP Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, false, addr,
+ json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN Multicast routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_imet,
+ show_bgp_vni_imet_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <3|multicast> [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_IMET_ROUTE, false, addr,
+ json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MACIP MAC routing table - for select VNI & MAC
+ */
+DEFPY(show_bgp_vni_macip_mac_addr,
+ show_bgp_vni_macip_mac_addr_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac X:X:X:X:X:X [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ MAC_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_route_vni_macip(vty, bgp, vni, &mac->eth_addr, NULL, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MACIP IP routing table - for select VNI & IP
+ */
+DEFPY(show_bgp_vni_macip_ip_addr, show_bgp_vni_macip_ip_addr_cmd,
+ "show bgp vni " CMD_VNI_RANGE
+ "$vni type <2|macip> ip <A.B.C.D|X:X::X:X> [json$uj]",
+ SHOW_STR BGP_STR VNI_HELP_STR VNI_NUM_HELP_STR EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR
+ "IP Table\n" IP_ADDR_STR IP6_ADDR_STR JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+ struct ipaddr ip_addr = {.ipa_type = IPADDR_NONE};
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ if (sockunion_family(ip) == AF_INET) {
+ ip_addr.ipa_type = IPADDR_V4;
+ ip_addr.ipaddr_v4.s_addr = sockunion2ip(ip);
+ } else {
+ ip_addr.ipa_type = IPADDR_V6;
+ memcpy(&ip_addr.ipaddr_v6, &ip->sin6.sin6_addr,
+ sizeof(struct in6_addr));
+ }
+ evpn_show_route_vni_macip(vty, bgp, vni, NULL, &ip_addr, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
return CMD_SUCCESS;
}
@@ -6590,6 +7169,20 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
+ /* "show bgp vni" commands. */
+ install_element(VIEW_NODE, &show_bgp_vni_all_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_ead_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_macip_mac_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_macip_ip_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_imet_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_ead_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_mac_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_ip_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_imet_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_mac_addr_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_ip_addr_cmd);
+
/* "show bgp evpn" commands. */
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h
index 137365ddb..6b17a83b7 100644
--- a/bgpd/bgp_evpn_vty.h
+++ b/bgpd/bgp_evpn_vty.h
@@ -27,6 +27,12 @@ extern void bgp_ethernetvpn_init(void);
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
#define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
+#define VNI_HELP_STR "VXLAN Network Identifier\n"
+#define VNI_NUM_HELP_STR "VNI number\n"
+#define VNI_ALL_HELP_STR "All VNIs\n"
+#define DETAIL_HELP_STR "Print Detailed Output\n"
+#define VTEP_HELP_STR "Remote VTEP\n"
+#define VTEP_IP_HELP_STR "Remote VTEP IP address\n"
extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc,
int *oly_idx,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 48e154716..1b04bfc71 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -218,7 +218,10 @@ struct bgp_path_info_extra {
* For imported routes into a VNI (or VRF)
*/
void *parent; /* parent from global table */
- struct ethaddr mac; /* MAC set here for VNI table */
+ union {
+ struct ethaddr mac; /* MAC set here for VNI IP table */
+ struct ipaddr ip; /* IP set here for VNI MAC table */
+ } vni_info;
/*
* Some tunnelish parameters follow. Maybe consolidate into an
diff --git a/lib/command.h b/lib/command.h
index 70e52708a..b701d4d0e 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -404,6 +404,8 @@ struct cmd_node {
#define SHOW_STR "Show running system information\n"
#define IP_STR "IP information\n"
#define IPV6_STR "IPv6 information\n"
+#define IP_ADDR_STR "IPv4 Address\n"
+#define IP6_ADDR_STR "IPv6 Address\n"
#define SRTE_STR "SR-TE information\n"
#define SRTE_COLOR_STR "SR-TE Color information\n"
#define NO_STR "Negate a command or set its defaults\n"
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 168f0b2ce..e37f56f0e 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -1327,11 +1327,11 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
uint8_t flags, uint32_t seq,
const esi_t *esi)
{
- struct sync_mac_ip_ctx ctx;
char ipbuf[INET6_ADDRSTRLEN];
bool sticky;
bool remote_gw;
struct zebra_neigh *n = NULL;
+ struct zebra_mac *mac = NULL;
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
@@ -1352,22 +1352,30 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
return;
}
- if (ipa_len) {
+ if (!ipa_len) {
+ /* MAC update */
+ (void)zebra_evpn_proc_sync_mac_update(zevpn, macaddr, ipa_len,
+ ipaddr, flags, seq, esi);
+ } else {
+ /* MAC-IP update */
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr,
+ ipa_len, ipaddr,
+ flags, seq, esi);
+ }
+ if (!mac)
+ return;
+
n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
if (n
&& !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq,
true))
return;
- }
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.mac = zebra_evpn_proc_sync_mac_update(
- zevpn, macaddr, ipa_len, ipaddr, flags, seq, esi, &ctx);
- if (ctx.ignore_macip || !ctx.mac || !ipa_len)
- return;
- zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, flags, seq,
- esi, &ctx);
+ zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr,
+ flags, seq, esi, mac);
+ }
}
/************************** remote mac-ip handling **************************/
@@ -1452,14 +1460,30 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
}
zvrf = zebra_vrf_get_evpn();
- if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len,
- ipaddr, &mac, vtep_ip, flags, seq,
- esi)
- != 0)
+ if (!zvrf)
return;
- zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip,
- flags, seq);
+ if (!ipa_len) {
+ /* MAC update */
+ zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, vtep_ip,
+ flags, seq, esi);
+ } else {
+ /* MAC-IP update
+ * Add auto MAC if it doesn't exist.
+ */
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ mac = zebra_evpn_mac_add_auto(zevpn, macaddr);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Neigh %pIA: MAC %pEA not found, Auto MAC created",
+ ipaddr, macaddr);
+ }
+
+ zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac,
+ vtep_ip, flags, seq);
+ }
}
/* Process a remote MACIP delete from BGP. */
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 4300b55c3..f0d256e28 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -1179,6 +1179,25 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
return 0;
}
+/*
+ * Add Auto MAC entry.
+ */
+struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
+ const struct ethaddr *macaddr)
+{
+ struct zebra_mac *mac;
+
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!mac)
+ return NULL;
+
+ zebra_evpn_mac_clear_fwd_info(mac);
+ memset(&mac->flags, 0, sizeof(uint32_t));
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+
+ return mac;
+}
+
static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
struct zebra_mac *mac)
{
@@ -1592,11 +1611,8 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
struct zebra_mac *mac,
- uint32_t seq, uint16_t ipa_len,
- const struct ipaddr *ipaddr,
- bool sync)
+ uint32_t seq, bool sync)
{
- char ipbuf[INET6_ADDRSTRLEN];
char mac_buf[MAC_BUF_SIZE];
uint32_t tmp_seq;
const char *n_type;
@@ -1630,14 +1646,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
IS_ZEBRA_DEBUG_VXLAN) {
zlog_debug(
- "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
+ "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
sync ? "sync" : "rem", zevpn->vni,
- n_type, &mac->macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf))
- : "",
- tmp_seq,
+ n_type, &mac->macaddr, tmp_seq,
zebra_evpn_zebra_mac_flag_dump(
mac, mac_buf, sizeof(mac_buf)));
}
@@ -1647,14 +1658,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
zlog_debug(
- "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
+ "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
sync ? "sync" : "rem", zevpn->vni, n_type,
- &mac->macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf))
- : "",
- tmp_seq,
+ &mac->macaddr, tmp_seq,
zebra_evpn_zebra_mac_flag_dump(
mac, mac_buf, sizeof(mac_buf)));
}
@@ -1665,10 +1671,12 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
return true;
}
-struct zebra_mac *zebra_evpn_proc_sync_mac_update(
- struct zebra_evpn *zevpn, const struct ethaddr *macaddr,
- uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
- uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx)
+struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
+ const struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ const struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ const esi_t *esi)
{
struct zebra_mac *mac;
bool inform_bgp = false;
@@ -1680,6 +1688,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
bool old_local = false;
bool old_bgp_ready;
bool new_bgp_ready;
+ bool created = false;
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
@@ -1688,8 +1697,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
*/
inform_bgp = true;
inform_dataplane = true;
- ctx->mac_created = true;
- ctx->mac_inactive = true;
/* create the MAC and associate it with the dest ES */
mac = zebra_evpn_mac_add(zevpn, macaddr);
@@ -1707,6 +1714,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
old_bgp_ready = false;
new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ created = true;
} else {
uint32_t old_flags;
uint32_t new_flags;
@@ -1731,14 +1739,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
: "",
sticky ? " sticky" : "",
remote_gw ? " remote_gw" : "");
- ctx->ignore_macip = true;
return NULL;
}
- if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
- ipaddr, true)) {
- ctx->ignore_macip = true;
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
return NULL;
- }
old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
old_static = zebra_evpn_mac_is_static(mac);
@@ -1747,12 +1751,11 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
new_flags = 0;
SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
/* retain old local activity flag */
- if (old_flags & ZEBRA_MAC_LOCAL) {
+ if (old_flags & ZEBRA_MAC_LOCAL)
new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
- } else {
+ else
new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
- ctx->mac_inactive = true;
- }
+
if (ipa_len) {
/* if mac-ip route do NOT update the peer flags
* i.e. retain only flags as is
@@ -1805,7 +1808,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
if (es_change) {
inform_bgp = true;
inform_dataplane = true;
- ctx->mac_inactive = true;
}
/* if peer-flag is being set notify dataplane that the
@@ -1836,8 +1838,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
char mac_buf[MAC_BUF_SIZE];
zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
- ctx->mac_created ? "created" : "updated",
- zevpn->vni, macaddr,
+ created ? "created" : "updated", zevpn->vni, macaddr,
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
sizeof(mac_buf)),
@@ -1856,22 +1857,15 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
zebra_evpn_process_neigh_on_local_mac_change(
zevpn, mac, seq_change, es_change);
- if (inform_dataplane) {
- if (ipa_len)
- /* if the mac is being created as a part of MAC-IP
- * route wait for the neigh to be updated or
- * created before programming the mac
- */
- ctx->mac_dp_update_deferred = true;
- else
- /* program the local mac in the kernel. when the ES
- * change we need to force the dataplane to reset
- * the activity as we are yet to establish activity
- * locally
- */
- zebra_evpn_sync_mac_dp_install(
- mac, ctx->mac_inactive,
- false /* force_clear_static */, __func__);
+ if (inform_dataplane && !ipa_len) {
+ /* program the local mac in the kernel. when the ES
+ * change we need to force the dataplane to reset
+ * the activity as we are yet to establish activity
+ * locally
+ */
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
}
return mac;
@@ -1995,13 +1989,12 @@ void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
zebra_evpn_print_mac_hash_detail(bucket, ctxt);
}
-int zebra_evpn_mac_remote_macip_add(
- struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
- const struct ethaddr *macaddr, uint16_t ipa_len,
- const struct ipaddr *ipaddr, struct zebra_mac **macp,
- struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi)
+int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
+ struct zebra_vrf *zvrf,
+ const struct ethaddr *macaddr,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, const esi_t *esi)
{
- char buf1[INET6_ADDRSTRLEN];
bool sticky;
bool remote_gw;
int update_mac = 0;
@@ -2023,11 +2016,8 @@ int zebra_evpn_mac_remote_macip_add(
&& CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
- zevpn->vni, macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
- : "");
+ "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
+ zevpn->vni, macaddr);
return -1;
}
@@ -2048,10 +2038,6 @@ int zebra_evpn_mac_remote_macip_add(
if (!mac) {
mac = zebra_evpn_mac_add(zevpn, macaddr);
zebra_evpn_es_mac_ref(mac, esi);
-
- /* Is this MAC created for a MACIP? */
- if (ipa_len)
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
} else {
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
@@ -2061,8 +2047,8 @@ int zebra_evpn_mac_remote_macip_add(
* the sequence number and ignore this update
* if appropriate.
*/
- if (!zebra_evpn_mac_is_bgp_seq_ok(
- zevpn, mac, seq, ipa_len, ipaddr, false))
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
+ false))
return -1;
old_es_present = !!mac->es;
@@ -2146,12 +2132,7 @@ int zebra_evpn_mac_remote_macip_add(
/* Update seq number. */
mac->rem_seq = seq;
- /* If there is no IP, return after clearing AUTO flag of MAC. */
- if (!ipa_len) {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- return -1;
- }
- *macp = mac;
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
return 0;
}
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index b727ac1f9..9b4ea2b79 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -176,17 +176,6 @@ struct rmac_walk_ctx {
struct json_object *json;
};
-/* temporary datastruct to pass info between the mac-update and
- * neigh-update while handling mac-ip routes
- */
-struct sync_mac_ip_ctx {
- bool ignore_macip;
- bool mac_created;
- bool mac_inactive;
- bool mac_dp_update_deferred;
- struct zebra_mac *mac;
-};
-
/**************************** SYNC MAC handling *****************************/
/* if the mac has been added of a mac-route from the peer
* or if it is being referenced by a neigh added by the
@@ -232,6 +221,8 @@ struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevi,
const struct ethaddr *mac);
struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevi,
const struct ethaddr *macaddr);
+struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevi,
+ const struct ethaddr *macaddr);
int zebra_evpn_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac);
int zebra_evpn_macip_send_msg_to_client(uint32_t id,
const struct ethaddr *macaddr,
@@ -255,20 +246,22 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
uint32_t flags, bool force);
void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevi);
-struct zebra_mac *zebra_evpn_proc_sync_mac_update(
- struct zebra_evpn *zevi, const struct ethaddr *macaddr,
- uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
- uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx);
+struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevi,
+ const struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ const struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ const esi_t *esi);
void zebra_evpn_sync_mac_del(struct zebra_mac *mac);
void zebra_evpn_rem_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac);
void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt);
void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
void *ctxt);
-int zebra_evpn_mac_remote_macip_add(
- struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
- const struct ethaddr *macaddr, uint16_t ipa_len,
- const struct ipaddr *ipaddr, struct zebra_mac **macp,
- struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi);
+int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
+ struct zebra_vrf *zvrf,
+ const struct ethaddr *macaddr,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, const esi_t *esi);
int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
struct zebra_evpn *zevpn,
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 7b5f1fc24..470bbdb60 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -626,11 +626,10 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n)
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
- const esi_t *esi, struct sync_mac_ip_ctx *ctx)
+ const esi_t *esi, struct zebra_mac *mac)
{
struct interface *ifp = NULL;
bool is_router;
- struct zebra_mac *mac = ctx->mac;
uint32_t tmp_seq;
bool old_router = false;
bool old_bgp_ready = false;
@@ -791,8 +790,8 @@ struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
inform_bgp = true;
new_mac_static = zebra_evpn_mac_is_static(mac);
- if ((old_mac_static != new_mac_static) || ctx->mac_dp_update_deferred)
- zebra_evpn_sync_mac_dp_install(mac, ctx->mac_inactive,
+ if (old_mac_static != new_mac_static)
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
false /* force_clear_static */,
__func__);
@@ -1286,10 +1285,12 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u",
macaddr, ip, zevpn->vni);
- zmac = zebra_evpn_mac_add(zevpn, macaddr);
- zebra_evpn_mac_clear_fwd_info(zmac);
- memset(&zmac->flags, 0, sizeof(uint32_t));
- SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ zmac = zebra_evpn_mac_add_auto(zevpn, macaddr);
+ if (!zmac) {
+ zlog_debug("Failed to add MAC %pEA VNI %u", macaddr,
+ zevpn->vni);
+ return -1;
+ }
} else {
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
/*
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
index c779109e0..927181744 100644
--- a/zebra/zebra_evpn_neigh.h
+++ b/zebra/zebra_evpn_neigh.h
@@ -231,7 +231,7 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n);
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
- const esi_t *esi, struct sync_mac_ip_ctx *ctx);
+ const esi_t *esi, struct zebra_mac *mac);
void zebra_evpn_neigh_del_all(struct zebra_evpn *zevpn, int uninstall,
int upd_client, uint32_t flags);
struct zebra_neigh *zebra_evpn_neigh_lookup(struct zebra_evpn *zevpn,