summaryrefslogtreecommitdiff
path: root/zebra/zebra_vxlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_vxlan.c')
-rw-r--r--zebra/zebra_vxlan.c198
1 files changed, 122 insertions, 76 deletions
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index b6da445e38..13e1f63457 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -62,6 +62,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
DEFINE_MTYPE_STATIC(ZEBRA, L3VNI_MAC, "EVPN L3VNI MAC");
DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor");
DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
+DEFINE_MTYPE_STATIC(ZEBRA, EVPN_VTEP, "zebra VxLAN VTEP IP");
DEFINE_HOOK(zebra_rmac_update,
(struct zebra_mac * rmac, struct zebra_l3vni *zl3vni, bool delete,
@@ -198,6 +199,37 @@ static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe)
return count;
}
+static int l3vni_rmac_nh_list_cmp(void *p1, void *p2)
+{
+ const struct ipaddr *vtep_ip1 = p1;
+ const struct ipaddr *vtep_ip2 = p2;
+
+ return !ipaddr_cmp(vtep_ip1, vtep_ip2);
+}
+
+static void l3vni_rmac_nh_free(struct ipaddr *vtep_ip)
+{
+ XFREE(MTYPE_EVPN_VTEP, vtep_ip);
+}
+
+static void l3vni_rmac_nh_list_nh_delete(struct zebra_l3vni *zl3vni,
+ struct zebra_mac *zrmac,
+ struct ipaddr *vtep_ip)
+{
+ struct listnode *node = NULL, *nnode = NULL;
+ struct ipaddr *vtep = NULL;
+
+ for (ALL_LIST_ELEMENTS(zrmac->nh_list, node, nnode, vtep)) {
+ if (ipaddr_cmp(vtep, vtep_ip) == 0)
+ break;
+ }
+
+ if (node) {
+ l3vni_rmac_nh_free(vtep);
+ list_delete_node(zrmac->nh_list, node);
+ }
+}
+
/*
* Print neighbors for all EVPN.
*/
@@ -366,35 +398,25 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
static void zl3vni_print_rmac(struct zebra_mac *zrmac, struct vty *vty,
json_object *json)
{
- char buf1[ETHER_ADDR_STRLEN];
- char buf2[PREFIX_STRLEN];
- json_object *json_hosts = NULL;
- struct host_rb_entry *hle;
+ struct listnode *node = NULL;
+ struct ipaddr *vtep = NULL;
+ json_object *json_nhs = NULL;
if (!json) {
- vty_out(vty, "MAC: %s\n",
- prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
+ vty_out(vty, "MAC: %pEA\n", &zrmac->macaddr);
vty_out(vty, " Remote VTEP: %pI4\n",
&zrmac->fwd_info.r_vtep_ip);
- vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb));
- vty_out(vty, " Prefixes:\n");
- RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
- vty_out(vty, " %pFX\n", &hle->p);
} else {
- json_hosts = json_object_new_array();
- json_object_string_add(
- json, "routerMac",
- prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
+ json_nhs = json_object_new_array();
+ json_object_string_addf(json, "routerMac", "%pEA",
+ &zrmac->macaddr);
json_object_string_addf(json, "vtepIp", "%pI4",
&zrmac->fwd_info.r_vtep_ip);
- json_object_int_add(json, "refCount",
- rb_host_count(&zrmac->host_rb));
- RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
- json_object_array_add(
- json_hosts,
- json_object_new_string(prefix2str(
- &hle->p, buf2, sizeof(buf2))));
- json_object_object_add(json, "prefixList", json_hosts);
+ for (ALL_LIST_ELEMENTS_RO(zrmac->nh_list, node, vtep)) {
+ json_object_array_add(json_nhs, json_object_new_stringf(
+ "%pIA", vtep));
+ }
+ json_object_object_add(json, "nexthops", json_nhs);
}
}
@@ -826,8 +848,7 @@ static int zvni_map_to_svi_ns(struct ns *ns,
struct interface **p_ifp = (struct interface **)_p_ifp;
struct zebra_if *zif;
- if (!in_param)
- return NS_WALK_STOP;
+ assert(in_param && p_ifp);
/* TODO: Optimize with a hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
@@ -842,8 +863,7 @@ static int zvni_map_to_svi_ns(struct ns *ns,
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
if (vl->vid == in_param->vid) {
- if (p_ifp)
- *p_ifp = tmp_if;
+ *p_ifp = tmp_if;
return NS_WALK_STOP;
}
}
@@ -1070,13 +1090,11 @@ static void zebra_evpn_vxlan_cleanup_all(struct hash_bucket *bucket, void *arg)
{
struct zebra_evpn *zevpn = NULL;
struct zebra_l3vni *zl3vni = NULL;
- struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
zevpn = (struct zebra_evpn *)bucket->data;
- /* remove from l3-vni list */
- if (zvrf->l3vni)
- zl3vni = zl3vni_lookup(zvrf->l3vni);
+ /* remove l2vni from l2vni's tenant-vrf l3-vni list */
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
if (zl3vni)
listnode_delete(zl3vni->l2vnis, zevpn);
@@ -1173,7 +1191,9 @@ static struct zebra_mac *zl3vni_rmac_add(struct zebra_l3vni *zl3vni,
zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
assert(zrmac);
- RB_INIT(host_rb_tree_entry, &zrmac->host_rb);
+ zrmac->nh_list = list_new();
+ zrmac->nh_list->cmp = (int (*)(void *, void *))l3vni_rmac_nh_list_cmp;
+ zrmac->nh_list->del = (void (*)(void *))l3vni_rmac_nh_free;
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE);
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC);
@@ -1187,14 +1207,9 @@ static struct zebra_mac *zl3vni_rmac_add(struct zebra_l3vni *zl3vni,
static int zl3vni_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac)
{
struct zebra_mac *tmp_rmac;
- struct host_rb_entry *hle;
- while (!RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
- hle = RB_ROOT(host_rb_tree_entry, &zrmac->host_rb);
-
- RB_REMOVE(host_rb_tree_entry, &zrmac->host_rb, hle);
- XFREE(MTYPE_HOST_PREFIX, hle);
- }
+ /* free the list of nh list*/
+ list_delete(&zrmac->nh_list);
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
XFREE(MTYPE_L3VNI_MAC, tmp_rmac);
@@ -1295,10 +1310,10 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
/* handle rmac add */
static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni,
const struct ethaddr *rmac,
- const struct ipaddr *vtep_ip,
- const struct prefix *host_prefix)
+ const struct ipaddr *vtep_ip)
{
struct zebra_mac *zrmac = NULL;
+ struct ipaddr *vtep = NULL;
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
if (!zrmac) {
@@ -1307,13 +1322,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni,
zrmac = zl3vni_rmac_add(zl3vni, rmac);
if (!zrmac) {
zlog_debug(
- "Failed to add RMAC %pEA L3VNI %u Remote VTEP %pIA, prefix %pFX",
- rmac, zl3vni->vni, vtep_ip, host_prefix);
+ "Failed to add RMAC %pEA L3VNI %u Remote VTEP %pIA",
+ rmac, zl3vni->vni, vtep_ip);
return -1;
}
memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
+ vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr));
+ memcpy(vtep, vtep_ip, sizeof(struct ipaddr));
+ if (!listnode_add_sort_nodup(zrmac->nh_list, (void *)vtep))
+ XFREE(MTYPE_EVPN_VTEP, vtep);
+
/* Send RMAC for FPM processing */
hook_call(zebra_rmac_update, zrmac, zl3vni, false,
"new RMAC added");
@@ -1324,18 +1344,21 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni,
&vtep_ip->ipaddr_v4)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA, prefix %pFX",
+ "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA",
zl3vni->vni, &zrmac->fwd_info.r_vtep_ip,
- vtep_ip, rmac, host_prefix);
+ vtep_ip, rmac);
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
+ vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr));
+ memcpy(vtep, vtep_ip, sizeof(struct ipaddr));
+ if (!listnode_add_sort_nodup(zrmac->nh_list, (void *)vtep))
+ XFREE(MTYPE_EVPN_VTEP, vtep);
+
/* install rmac in kernel */
zl3vni_rmac_install(zl3vni, zrmac);
}
- rb_find_or_add_host(&zrmac->host_rb, host_prefix);
-
return 0;
}
@@ -1343,20 +1366,59 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni,
/* handle rmac delete */
static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni,
struct zebra_mac *zrmac,
- struct prefix *host_prefix)
+ struct ipaddr *vtep_ip)
{
- rb_delete_host(&zrmac->host_rb, host_prefix);
+ struct ipaddr ipv4_vtep;
- if (RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
- /* uninstall from kernel */
- zl3vni_rmac_uninstall(zl3vni, zrmac);
+ if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) {
+ memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
+ ipv4_vtep.ipa_type = IPADDR_V4;
+ if (vtep_ip->ipa_type == IPADDR_V6)
+ ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
+ &ipv4_vtep.ipaddr_v4);
+ else
+ memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
+ sizeof(struct in_addr));
- /* Send RMAC for FPM processing */
- hook_call(zebra_rmac_update, zrmac, zl3vni, true,
- "RMAC deleted");
+ /* remove nh from rmac's list */
+ l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep);
+ /* delete nh is same as current selected, fall back to
+ * one present in the list
+ */
+ if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip,
+ &ipv4_vtep.ipaddr_v4) &&
+ listcount(zrmac->nh_list)) {
+ struct ipaddr *vtep;
+
+ vtep = listgetdata(listhead(zrmac->nh_list));
+ zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4;
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA",
+ zl3vni->vni, &ipv4_vtep,
+ &zrmac->fwd_info.r_vtep_ip,
+ &zrmac->macaddr);
+
+ /* install rmac in kernel */
+ zl3vni_rmac_install(zl3vni, zrmac);
+ }
- /* del the rmac entry */
- zl3vni_rmac_del(zl3vni, zrmac);
+ if (!listcount(zrmac->nh_list)) {
+ /* uninstall from kernel */
+ zl3vni_rmac_uninstall(zl3vni, zrmac);
+
+ /* Send RMAC for FPM processing */
+ hook_call(zebra_rmac_update, zrmac, zl3vni, true,
+ "RMAC deleted");
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "L3VNI %u RMAC %pEA vtep_ip %pIA delete",
+ zl3vni->vni, &zrmac->macaddr, vtep_ip);
+
+ /* del the rmac entry */
+ zl3vni_rmac_del(zl3vni, zrmac);
+ }
}
}
@@ -2124,13 +2186,6 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
return 0;
zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- flog_err(EC_ZEBRA_VNI_ADD_FAILED,
- "Adding L2-VNI - Failed to add VNI hash, VNI %u",
- vni);
-
- return -1;
- }
/* Find bridge interface for the VNI */
vlan_if = zvni_map_to_svi(vxl->access_vlan,
@@ -2246,7 +2301,7 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
* add the rmac - remote rmac to be installed is against the ipv4
* nexthop address
*/
- zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
+ zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep);
}
/* handle evpn vrf route delete */
@@ -2273,8 +2328,7 @@ void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
/* delete the rmac entry */
if (zrmac)
- zl3vni_remote_rmac_del(zl3vni, zrmac, host_prefix);
-
+ zl3vni_remote_rmac_del(zl3vni, zrmac, vtep_ip);
}
void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
@@ -2308,7 +2362,7 @@ void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
vty_out(vty, "{}\n");
else
vty_out(vty,
- "%% Requested RMAC doesn't exist in L3-VNI %u",
+ "%% Requested RMAC doesn't exist in L3-VNI %u\n",
l3vni);
return;
}
@@ -5171,16 +5225,8 @@ int zebra_vxlan_if_add(struct interface *ifp)
/* Create or update EVPN hash. */
zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
+ if (!zevpn)
zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- flog_err(
- EC_ZEBRA_VNI_ADD_FAILED,
- "Failed to add EVPN hash, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
- }
if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {