+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Zebra EVPN for VxLAN code
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
*/
#include <zebra.h>
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
#include "zebra/zebra_evpn_neigh.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_vxlan.h"
#include "zebra/zebra_router.h"
const char *reason),
(rmac, zl3vni, delete, reason));
+/* config knobs */
+static bool accept_bgp_seq = true;
+
+/* Single VXlan Device Global Neigh Table */
+struct hash *svd_nh_table;
+
/* static function declarations */
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
void **args);
static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
struct zebra_neigh *n);
+static struct zebra_neigh *svd_nh_add(const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac);
+static int svd_nh_del(struct zebra_neigh *n);
+static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
+static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
/* l3-vni rmac related APIs */
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
static void *zl3vni_alloc(void *p);
static struct zebra_l3vni *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
static int zl3vni_del(struct zebra_l3vni *zl3vni);
-static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni);
-static void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni);
static void zevpn_build_hash_table(void);
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf,
struct in_addr sip,
struct in_addr mcast_grp);
-static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp);
-static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp);
static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf);
bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf)
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
vty_out(vty, " RMAC: %s\n",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- vty_out(vty, " Refcount: %d\n",
- rb_host_count(&n->host_rb));
- vty_out(vty, " Prefixes:\n");
- RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
- vty_out(vty, " %pFX\n", &hle->p);
+ if (n->refcnt)
+ /* SVD neigh */
+ vty_out(vty, " Refcount: %u\n", n->refcnt);
+ else {
+ vty_out(vty, " Refcount: %d\n",
+ rb_host_count(&n->host_rb));
+ vty_out(vty, " Prefixes:\n");
+ RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
+ vty_out(vty, " %pFX\n", &hle->p);
+ }
} else {
json_hosts = json_object_new_array();
json_object_string_add(
json_object_string_add(
json, "routerMac",
prefix_mac2str(&n->emac, buf2, sizeof(buf2)));
- json_object_int_add(json, "refCount",
- rb_host_count(&n->host_rb));
- RB_FOREACH (hle, host_rb_tree_entry, &n->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);
+ if (n->refcnt)
+ /* SVD neigh */
+ json_object_int_add(json, "refCount", n->refcnt);
+ else {
+ json_object_int_add(json, "refCount",
+ rb_host_count(&n->host_rb));
+ RB_FOREACH (hle, host_rb_tree_entry, &n->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);
+ }
}
}
}
}
-static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
- void **args)
+static void zl3vni_print_nh_all_table(struct hash *nh_table, vni_t vni,
+ struct vty *vty, json_object *json)
{
- struct vty *vty = NULL;
- json_object *json = NULL;
- json_object *json_evpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
uint32_t num_nh = 0;
struct nh_walk_ctx wctx;
char vni_str[VNI_STR_LEN];
+ json_object *json_evpn = NULL;
+ bool is_svd = false;
+ const char *svd_str = "Global SVD Table";
- vty = (struct vty *)args[0];
- json = (struct json_object *)args[1];
+ if (vni == 0)
+ is_svd = true;
- zl3vni = (struct zebra_l3vni *)bucket->data;
+ num_nh = hashcount(nh_table);
- num_nh = hashcount(zl3vni->nh_table);
if (!num_nh)
return;
if (json) {
json_evpn = json_object_new_object();
- snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+
+ snprintf(vni_str, VNI_STR_LEN, "%u", vni);
}
if (json == NULL) {
- vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh);
+ if (is_svd)
+ vty_out(vty, "\n%s #Next-Hops %u\n\n", svd_str, num_nh);
+ else
+ vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", vni, num_nh);
+
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
} else
json_object_int_add(json_evpn, "numNextHops", num_nh);
memset(&wctx, 0, sizeof(wctx));
wctx.vty = vty;
wctx.json = json_evpn;
- hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+ hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
if (json)
json_object_object_add(json, vni_str, json_evpn);
}
+static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
+ void **args)
+{
+ struct vty *vty = NULL;
+ json_object *json = NULL;
+ struct zebra_l3vni *zl3vni = NULL;
+
+ vty = (struct vty *)args[0];
+ json = (struct json_object *)args[1];
+
+ zl3vni = (struct zebra_l3vni *)bucket->data;
+
+ zl3vni_print_nh_all_table(zl3vni->nh_table, zl3vni->vni, vty, json);
+}
+
static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
void **args)
{
vty_out(vty, "VNI: %u\n", zl3vni->vni);
vty_out(vty, " Type: %s\n", "L3");
vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni));
+ vty_out(vty, " Vlan: %u\n", zl3vni->vid);
+ vty_out(vty, " Bridge: %s\n",
+ zl3vni->bridge_if ? zl3vni->bridge_if->name : "-");
vty_out(vty, " Local Vtep Ip: %pI4\n",
&zl3vni->local_vtep_ip);
vty_out(vty, " Vxlan-Intf: %s\n",
json_evpn_list = json_object_new_array();
json_object_int_add(json, "vni", zl3vni->vni);
json_object_string_add(json, "type", "L3");
+#if CONFDATE > 20240210
+CPP_NOTICE("Drop `vrf` from JSON outputs")
+#endif
+ json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
+ json_object_string_add(json, "tenantVrf",
+ zl3vni_vrf_name(zl3vni));
json_object_string_addf(json, "localVtepIp", "%pI4",
&zl3vni->local_vtep_ip);
json_object_string_add(json, "vxlanIntf",
json_object_string_add(json, "sviIntf",
zl3vni_svi_if_name(zl3vni));
json_object_string_add(json, "state", zl3vni_state2str(zl3vni));
- json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
json_object_string_add(
json, "sysMac",
zl3vni_sysmac2str(zl3vni, buf, sizeof(buf)));
{
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
struct zebra_from_svi_param in_param;
struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
/* Check oper status of the SVI. */
if (!in_param.bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
return tmp_if;
}
-static int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
+int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
{
+ zevpn->vid = 0;
zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */);
+ zevpn_bridge_if_set(zevpn, zevpn->bridge_if, false /* set */);
/* Remove references to the BUM mcast grp */
zebra_vxlan_sg_deref(zevpn->local_vtep_ip, zevpn->mcast_grp);
return zebra_evpn_del(zevpn);
}
+static int zevpn_build_vni_hash_table(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vnip, void *arg)
+{
+ vni_t vni;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *ifp;
+ struct zebra_l2info_vxlan *vxl;
+ struct interface *br_if;
+
+ ifp = zif->ifp;
+ vxl = &zif->l2info.vxl;
+ vni = vnip->vni;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Build vni table for vni %u for Intf %s", vni,
+ ifp->name);
+
+ /* L3-VNI and L2-VNI are handled seperately */
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "create L3-VNI hash for Intf %s(%u) L3-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+
+ /* associate with vxlan_if */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ zl3vni->vxlan_if = ifp;
+
+ /*
+ * we need to associate with SVI.
+ * we can associate with svi-if only after association
+ * with vxlan-intf is complete
+ */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+ /* Associate l3vni to mac-vlan and extract VRR MAC */
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "create l3vni %u svi_if %s mac_vlan_if %s", vni,
+ zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
+ zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name
+ : "NIL");
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+ } else {
+ struct interface *vlan_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4",
+ ifp->name, ifp->ifindex, vni, &vxl->vtep_ip);
+
+ /*
+ * EVPN hash entry is expected to exist, if the BGP process is
+ * killed
+ */
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn) {
+ zlog_debug(
+ "EVPN hash already present for IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+
+ /*
+ * Inform BGP if intf is up and mapped to
+ * bridge.
+ */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if)
+ zebra_evpn_send_add_to_client(zevpn);
+
+ /* Send Local MAC-entries to client */
+ zebra_evpn_send_mac_list_to_client(zevpn);
+
+ /* Send Loval Neighbor entries to client */
+ zebra_evpn_send_neigh_to_client(zevpn);
+ } else {
+ zevpn = zebra_evpn_add(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
+
+ if (zevpn->local_vtep_ip.s_addr !=
+ vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
+ zebra_vxlan_sg_ref(vxl->vtep_ip,
+ vnip->mcast_grp);
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vnip->mcast_grp;
+ /* on local vtep-ip check if ES
+ * orig-ip needs to be updated
+ */
+ zebra_evpn_es_set_base_evpn(zevpn);
+ }
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ br_if = zif->brslave_info.br_if;
+ zevpn_bridge_if_set(zevpn, br_if, true /* set */);
+ vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if);
+ if (vlan_if) {
+ zevpn->vid = vnip->access_vlan;
+ zevpn->svi_if = vlan_if;
+ zevpn->vrf_id = vlan_if->vrf->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
+ if (zl3vni)
+ listnode_add_sort(zl3vni->l2vnis,
+ zevpn);
+ }
+
+ /*
+ * Inform BGP if intf is up and mapped to
+ * bridge.
+ */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if)
+ zebra_evpn_send_add_to_client(zevpn);
+ }
+ }
+
+ return 0;
+}
+
static int zevpn_build_hash_table_zns(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
/* Walk VxLAN interfaces and create EVPN hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- vni_t vni;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
continue;
vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Intf %s(%u) VNI %u, link not in same "
+ "Intf %s(%u) link not in same "
"namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vni);
+ ifp->name, ifp->ifindex);
continue;
}
- /* L3-VNI and L2-VNI are handled seperately */
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "create L3-VNI hash for Intf %s(%u) L3-VNI %u",
- ifp->name, ifp->ifindex, vni);
-
- /* associate with vxlan_if */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- zl3vni->vxlan_if = ifp;
- /*
- * we need to associate with SVI.
- * we can associate with svi-if only after association
- * with vxlan-intf is complete
- */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
-
- /* Associate l3vni to mac-vlan and extract VRR MAC */
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s",
- vni, zl3vni->svi_if ? zl3vni->svi_if->name
- : "NIL",
- zl3vni->mac_vlan_if ?
- zl3vni->mac_vlan_if->name : "NIL");
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
-
- } else {
- struct interface *vlan_if = NULL;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4",
- ifp->name, ifp->ifindex, vni,
- &vxl->vtep_ip);
-
- /* EVPN hash entry is expected to exist, if the BGP process is killed */
- zevpn = zebra_evpn_lookup(vni);
- if (zevpn) {
- zlog_debug(
- "EVPN hash already present for IF %s(%u) L2-VNI %u",
- ifp->name, ifp->ifindex, vni);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Building vni table for %s-if %s",
+ IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd",
+ ifp->name);
- /*
- * Inform BGP if intf is up and mapped to
- * bridge.
- */
- if (if_is_operative(ifp) &&
- zif->brslave_info.br_if)
- zebra_evpn_send_add_to_client(zevpn);
-
- /* Send Local MAC-entries to client */
- zebra_evpn_send_mac_list_to_client(zevpn);
-
- /* Send Loval Neighbor entries to client */
- zebra_evpn_send_neigh_to_client(zevpn);
- } else {
- zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
- ifp->name, ifp->ifindex, vni);
- return NS_WALK_CONTINUE;
- }
-
- if (zevpn->local_vtep_ip.s_addr !=
- vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr !=
- vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(
- zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip,
- vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES
- * orig-ip needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(
- vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(
- vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort(
- zl3vni->l2vnis, zevpn);
- }
-
- /*
- * Inform BGP if intf is up and mapped to
- * bridge.
- */
- if (if_is_operative(ifp) &&
- zif->brslave_info.br_if)
- zebra_evpn_send_add_to_client(zevpn);
- }
- }
+ zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table,
+ NULL);
}
return NS_WALK_CONTINUE;
}
struct zebra_mac *zrmac)
{
const struct zebra_if *zif = NULL, *br_zif = NULL;
- const struct zebra_l2info_vxlan *vxl = NULL;
+ const struct zebra_vxlan_vni *vni;
const struct interface *br_ifp;
enum zebra_dplane_result res;
vlanid_t vid;
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
br_zif = (const struct zebra_if *)br_ifp->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
- res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0, 0,
+ res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
+ vni->vni, zrmac->fwd_info.r_vtep_ip, 0, 0,
false /*was_static*/);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
struct zebra_mac *zrmac)
{
const struct zebra_if *zif = NULL, *br_zif;
- const struct zebra_l2info_vxlan *vxl = NULL;
+ const struct zebra_vxlan_vni *vni;
const struct interface *br_ifp;
vlanid_t vid;
enum zebra_dplane_result res;
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
br_zif = (const struct zebra_if *)br_ifp->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
- res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip);
+ res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
+ vni->vni, zrmac->fwd_info.r_vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
}
/*
- * Look up nh hash entry on a l3-vni.
+ * Common code for look up of nh hash entry.
*/
-static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
- const struct ipaddr *ip)
+static struct zebra_neigh *_nh_lookup(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip)
{
struct zebra_neigh tmp;
struct zebra_neigh *n;
memset(&tmp, 0, sizeof(tmp));
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
- n = hash_lookup(zl3vni->nh_table, &tmp);
+
+ if (zl3vni)
+ n = hash_lookup(zl3vni->nh_table, &tmp);
+ else
+ n = hash_lookup(svd_nh_table, &tmp);
return n;
}
+/*
+ * Look up nh hash entry on a l3-vni.
+ */
+static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip)
+{
+ return _nh_lookup(zl3vni, ip);
+}
+
+/*
+ * Look up nh hash entry on a SVD.
+ */
+static struct zebra_neigh *svd_nh_lookup(const struct ipaddr *ip)
+{
+ return _nh_lookup(NULL, ip);
+}
/*
* Callback to allocate NH hash entry on L3-VNI.
}
/*
- * Add neighbor entry.
+ * Common code for neigh add.
*/
-static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
- const struct ipaddr *ip,
- const struct ethaddr *mac)
+static struct zebra_neigh *_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
{
struct zebra_neigh tmp_n;
struct zebra_neigh *n = NULL;
memset(&tmp_n, 0, sizeof(tmp_n));
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
- n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+
+ if (zl3vni)
+ n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+ else
+ n = hash_get(svd_nh_table, &tmp_n, zl3vni_nh_alloc);
+
+ assert(n);
RB_INIT(host_rb_tree_entry, &n->host_rb);
return n;
}
+/*
+ * Add neighbor entry.
+ */
+static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
+{
+ return _nh_add(zl3vni, ip, mac);
+}
+
/*
* Delete neighbor entry.
*/
}
/*
- * Install remote nh as neigh into the kernel.
+ * Add Single VXlan Device neighbor entry.
*/
-static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+static struct zebra_neigh *svd_nh_add(const struct ipaddr *ip,
+ const struct ethaddr *mac)
+{
+ return _nh_add(NULL, ip, mac);
+}
+
+/*
+ * Del Single VXlan Device neighbor entry.
+ */
+static int svd_nh_del(struct zebra_neigh *n)
+{
+ if (n->refcnt > 0)
+ return -1;
+
+ hash_release(svd_nh_table, n);
+ XFREE(MTYPE_L3NEIGH, n);
+
+ return 0;
+}
+
+/*
+ * Common code to install remote nh as neigh into the kernel.
+ */
+static int _nh_install(struct zebra_l3vni *zl3vni, struct interface *ifp,
+ struct zebra_neigh *n)
{
uint8_t flags;
int ret = 0;
- if (!is_l3vni_oper_up(zl3vni))
+ if (zl3vni && !is_l3vni_oper_up(zl3vni))
return -1;
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
flags |= DPLANE_NTF_ROUTER;
- dplane_rem_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags,
- false /*was_static*/);
+ dplane_rem_neigh_add(ifp, &n->ip, &n->emac, flags,
+ false /*was_static*/);
return ret;
}
/*
- * Uninstall remote nh from the kernel.
+ * Common code to uninstall remote nh from the kernel.
*/
-static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
- struct zebra_neigh *n)
+static int _nh_uninstall(struct interface *ifp, struct zebra_neigh *n)
{
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
return 0;
- if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
+ if (!ifp || !if_is_operative(ifp))
return 0;
- dplane_rem_neigh_delete(zl3vni->svi_if, &n->ip);
+ dplane_rem_neigh_delete(ifp, &n->ip);
return 0;
}
-/* add remote vtep as a neigh entry */
+/*
+ * Install remote nh as neigh into the kernel.
+ */
+static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_install(zl3vni, zl3vni->svi_if, n);
+}
+
+/*
+ * Uninstall remote nh from the kernel.
+ */
+static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
+ struct zebra_neigh *n)
+{
+ return _nh_uninstall(zl3vni->svi_if, n);
+}
+
+/*
+ * Install SVD remote nh as neigh into the kernel.
+ */
+static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_install(zl3vni, zl3vni->vxlan_if, n);
+}
+
+/*
+ * Uninstall SVD remote nh from the kernel.
+ */
+static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_uninstall(zl3vni->vxlan_if, n);
+}
+
+/* Add remote vtep as a neigh entry */
static int zl3vni_remote_nh_add(struct zebra_l3vni *zl3vni,
const struct ipaddr *vtep_ip,
const struct ethaddr *rmac,
return 0;
}
-/* handle nh neigh delete */
+/* Del remote vtep as a neigh entry */
static void zl3vni_remote_nh_del(struct zebra_l3vni *zl3vni,
struct zebra_neigh *nh,
struct prefix *host_prefix)
}
}
-/* handle neigh update from kernel - the only thing of interest is to
- * readd stale entries.
- */
-static int zl3vni_local_nh_add_update(struct zebra_l3vni *zl3vni,
- struct ipaddr *ip, uint16_t state)
+/* Add remote vtep as a SVD neigh entry */
+static int svd_remote_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac,
+ const struct prefix *host_prefix)
{
-#ifdef GNU_LINUX
- struct zebra_neigh *n = NULL;
+ struct zebra_neigh *nh = NULL;
- n = zl3vni_nh_lookup(zl3vni, ip);
- if (!n)
+ /* SVD backed VNI check */
+ if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
return 0;
- /* all next hop neigh are remote and installed by frr.
- * If the kernel has aged this entry, re-install.
- */
- if (state & NUD_STALE)
- zl3vni_nh_install(zl3vni, n);
-#endif
- return 0;
-}
+ /* Create the SVD next hop entry, or update its mac, if necessary. */
+ nh = svd_nh_lookup(vtep_ip);
+ if (!nh) {
+ nh = svd_nh_add(vtep_ip, rmac);
+ if (!nh) {
+ zlog_debug(
+ "Failed to add NH %pIA as SVD Neigh (RMAC %pEA prefix %pFX)",
+ vtep_ip, rmac, host_prefix);
+ return -1;
+ }
-/* handle neigh delete from kernel */
-static int zl3vni_local_nh_del(struct zebra_l3vni *zl3vni, struct ipaddr *ip)
-{
- struct zebra_neigh *n = NULL;
+ } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "SVD RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX",
+ &nh->emac, rmac, vtep_ip, host_prefix);
+
+ memcpy(&nh->emac, rmac, ETH_ALEN);
+ /* install (update) the nh neigh in kernel */
+ svd_nh_install(zl3vni, nh);
+
+ /* Don't increment refcnt change */
+ return 0;
+ }
+
+ nh->refcnt++;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("SVD NH ADD refcnt (%u) for nexthop %pIA",
+ nh->refcnt, vtep_ip);
+
+ /*
+ * Install the nh neigh in kernel if this is the first time we
+ * have seen it.
+ */
+ if (nh->refcnt == 1)
+ svd_nh_install(zl3vni, nh);
+
+ return 0;
+}
+
+/* Del remote vtep as a SVD neigh entry */
+static int svd_remote_nh_del(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *vtep_ip)
+{
+ struct zebra_neigh *nh;
+
+ /* SVD backed VNI check */
+ if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
+ return 0;
+
+ nh = svd_nh_lookup(vtep_ip);
+ if (!nh) {
+ zlog_debug("Failed to del NH %pIA as SVD Neigh", vtep_ip);
+
+ return -1;
+ }
+
+ nh->refcnt--;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("SVD NH Del refcnt (%u) for nexthop %pIA",
+ nh->refcnt, vtep_ip);
+
+ /* Last refcnt on NH, remove it completely. */
+ if (nh->refcnt == 0) {
+ svd_nh_uninstall(zl3vni, nh);
+ svd_nh_del(nh);
+ }
+
+ return 0;
+}
+
+/* handle neigh update from kernel - the only thing of interest is to
+ * readd stale entries.
+ */
+static int zl3vni_local_nh_add_update(struct zebra_l3vni *zl3vni,
+ struct ipaddr *ip, uint16_t state)
+{
+#ifdef GNU_LINUX
+ struct zebra_neigh *n = NULL;
+
+ n = zl3vni_nh_lookup(zl3vni, ip);
+ if (!n)
+ return 0;
+
+ /* all next hop neigh are remote and installed by frr.
+ * If the kernel has aged this entry, re-install.
+ */
+ if (state & NUD_STALE)
+ zl3vni_nh_install(zl3vni, n);
+#endif
+ return 0;
+}
+
+/* handle neigh delete from kernel */
+static int zl3vni_local_nh_del(struct zebra_l3vni *zl3vni, struct ipaddr *ip)
+{
+ struct zebra_neigh *n = NULL;
n = zl3vni_nh_lookup(zl3vni, ip);
if (!n)
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni = NULL;
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni != zl3vni->vni)
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
+ if (!vni || vni->vni != zl3vni->vni)
continue;
/* link of VXLAN interface should be in zebra_evpn_vrf */
zlog_debug(
"Intf %s(%u) VNI %u, link not in same "
"namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vxl->vni);
+ ifp->name, ifp->ifindex, vni->vni);
continue;
}
- zl3vni->local_vtep_ip = vxl->vtep_ip;
+ zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
*_pifp = (void *)ifp;
return NS_WALK_STOP;
}
struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
{
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
- struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
+ struct zebra_vxlan_vni *vni = NULL; /* vni info in vxlan_if */
if (!zl3vni)
return NULL;
if (!zif)
return NULL;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
+ if (!vni)
+ return NULL;
- return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ return zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
}
struct interface *zl3vni_map_to_mac_vlan_if(struct zebra_l3vni *zl3vni)
static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
{
+ int found = 0;
+ vni_t vni_id = 0;
struct zebra_ns *zns = ns->info;
struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
struct zebra_from_svi_param *in_param =
struct route_node *rn = NULL;
struct interface *tmp_if = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_if *br_zif = NULL;
assert(in_param && p_zl3vni);
- /* loop through all vxlan-interface */
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
+ br_zif = in_param->br_if->info;
+ assert(br_zif);
- if (zif->brslave_info.br_if != in_param->br_if)
- continue;
+ if (in_param->bridge_vlan_aware) {
+ vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid);
+ if (vni_id)
+ found = 1;
+ } else {
+ /* loop through all vxlan-interface */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
- *p_zl3vni = zl3vni_lookup(vxl->vni);
- return NS_WALK_STOP;
+ if (zif->brslave_info.br_if != in_param->br_if)
+ continue;
+
+ vni_id = zebra_vxlan_if_access_vlan_vni_find(
+ zif, in_param->br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
- return NS_WALK_CONTINUE;
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ *p_zl3vni = zl3vni_lookup(vni_id);
+ return NS_WALK_STOP;
}
/*
{
struct zebra_l3vni *zl3vni = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_bridge *br = NULL;
struct zebra_from_svi_param in_param = {};
struct zebra_l3vni **p_zl3vni;
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
return zserv_send_message(client, s);
}
-static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
+void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
{
if (!zl3vni)
return;
zl3vni_send_add_to_client(zl3vni);
}
-static void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni)
+void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni)
{
if (!zl3vni)
return;
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;
+ struct zebra_vxlan_vni *vnip;
struct zebra_l2info_vxlan *vxl;
struct interface *vlan_if;
bool found = false;
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == vni) {
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (vnip) {
found = true;
break;
}
zevpn = zebra_evpn_add(vni);
/* Find bridge interface for the VNI */
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ vlan_if = zvni_map_to_svi(vnip->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
zevpn->vrf_id = vlan_if->vrf->vrf_id;
*/
zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+ /* Add SVD next hop neighbor */
+ svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+
/*
* if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
* address. Rmac is programmed against the ipv4 vtep because we only
/* delete the next hop entry */
zl3vni_remote_nh_del(zl3vni, nh, host_prefix);
+ /* Delete SVD next hop entry */
+ svd_remote_nh_del(zl3vni, vtep_ip);
+
/* delete the rmac entry */
if (zrmac)
zl3vni_remote_rmac_del(zl3vni, zrmac, vtep_ip);
if (use_json)
json = json_object_new_object();
- zl3vni = zl3vni_lookup(l3vni);
- if (!zl3vni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
- return;
+ /* If vni=0 passed, assume svd lookup */
+ if (!l3vni)
+ n = svd_nh_lookup(ip);
+ else {
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n",
+ l3vni);
+ return;
+ }
+
+ n = zl3vni_nh_lookup(zl3vni, ip);
}
- n = zl3vni_nh_lookup(zl3vni, ip);
if (!n) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty,
- "%% Requested next-hop not present for L3-VNI %u",
+ "%% Requested next-hop not present for L3-VNI %u\n",
l3vni);
return;
}
vty_json(vty, json);
}
-void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
+static void l3vni_print_nh_table(struct hash *nh_table, struct vty *vty,
+ bool use_json)
{
uint32_t num_nh;
struct nh_walk_ctx wctx;
json_object *json = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- if (!is_evpn_enabled())
- return;
-
- zl3vni = zl3vni_lookup(l3vni);
- if (!zl3vni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
- return;
- }
- num_nh = hashcount(zl3vni->nh_table);
+ num_nh = hashcount(nh_table);
if (!num_nh)
return;
} else
json_object_int_add(json, "numNextHops", num_nh);
- hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+ hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
if (use_json)
vty_json(vty, json);
}
+void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ if (!is_evpn_enabled()) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+ return;
+ }
+
+ l3vni_print_nh_table(zl3vni->nh_table, vty, use_json);
+}
+
+void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json)
+{
+ if (!is_evpn_enabled()) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ l3vni_print_nh_table(svd_nh_table, vty, use_json);
+}
+
void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json)
{
json_object *json = NULL;
* Display MACs for a VNI (VTY command handler).
*/
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni, bool use_json)
+ vni_t vni, bool use_json, bool detail)
{
struct zebra_evpn *zevpn;
uint32_t num_macs;
wctx.json = json_mac;
if (!use_json) {
- vty_out(vty,
- "Number of MACs (local and remote) known for this VNI: %u\n",
- num_macs);
- vty_out(vty,
- "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
- vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC", "Type",
- "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s");
+ if (detail) {
+ vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
+ zevpn->vni, num_macs);
+ } else {
+ vty_out(vty,
+ "Number of MACs (local and remote) known for this VNI: %u\n",
+ num_macs);
+ vty_out(vty,
+ "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
+ "Type", "Flags", "Intf/Remote ES/VTEP", "VLAN",
+ "Seq #'s");
+ }
} else
json_object_int_add(json, "numMacs", num_macs);
- hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, &wctx);
+ if (detail)
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash_detail,
+ &wctx);
+ else
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash,
+ &wctx);
if (use_json) {
json_object_object_add(json, "macs", json_mac);
json = json_object_new_object();
json_object_string_add(json, "advertiseGatewayMacip",
zvrf->advertise_gw_macip ? "Yes" : "No");
+ json_object_string_add(json, "advertiseSviMacip",
+ zvrf->advertise_svi_macip ? "Yes"
+ : "No");
+ json_object_string_add(json, "advertiseSviMac",
+ zebra_evpn_mh_do_adv_svi_mac() ? "Yes"
+ : "No");
json_object_int_add(json, "numVnis", num_vnis);
json_object_int_add(json, "numL2Vnis", num_l2vnis);
json_object_int_add(json, "numL3Vnis", num_l3vnis);
/*
* Handle remote vtep delete by kernel; re-add the vtep if we have it
*/
-int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+int zebra_vxlan_check_readd_vtep(struct interface *ifp, vni_t vni,
struct in_addr vtep_ip)
{
struct zebra_if *zif;
struct zebra_vrf *zvrf = NULL;
- struct zebra_l2info_vxlan *vxl;
- vni_t vni;
struct zebra_evpn *zevpn = NULL;
struct zebra_vtep *zvtep = NULL;
+ struct zebra_vxlan_vni *vnip;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* If EVPN is not enabled, nothing to do. */
if (!is_evpn_enabled())
if (!zvrf)
return -1;
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (!vnip)
+ return 0;
+
/* Locate hash entry; it is expected to exist. */
zevpn = zebra_evpn_lookup(vni);
if (!zevpn)
static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr,
- vlanid_t vid)
+ vlanid_t vid, vni_t vni)
{
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
- vni_t vni;
struct zebra_evpn *zevpn;
struct zebra_mac *mac;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
- uint32_t nhg_id, bool sticky, bool dp_static)
+ vni_t vni, uint32_t nhg_id, bool sticky,
+ bool dp_static)
{
struct zebra_evpn_es *es;
struct interface *acc_ifp;
}
/* Get vxlan's vid for netlink message has no it. */
- vid = ((struct zebra_if *)ifp->info)->l2info.vxl.access_vlan;
+ vid = ((struct zebra_if *)ifp->info)
+ ->l2info.vxl.vni_info.vni.access_vlan;
/* if remote mac delete the local entry */
if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr,
vid);
- return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr,
- vid);
+ return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr, vid,
+ vni);
}
/* If local MAC on a down local ES translate the network-mac-add
*/
int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
- struct ethaddr *macaddr, vlanid_t vid)
+ struct ethaddr *macaddr, vlanid_t vid,
+ vni_t vni)
{
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- vni_t vni;
struct zebra_evpn *zevpn = NULL;
struct zebra_l3vni *zl3vni = NULL;
struct zebra_mac *mac = NULL;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
}
}
-/*
- * Handle VxLAN interface down
- */
-int zebra_vxlan_if_down(struct interface *ifp)
+int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
+ char *err, int err_str_sz, int filter,
+ int add)
{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
struct zebra_l3vni *zl3vni = NULL;
- struct zebra_evpn *zevpn;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
+ struct zebra_vrf *zvrf_evpn = NULL;
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
+ zvrf_evpn = zebra_vrf_get_evpn();
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
- /* process-if-down for l3-vni */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name,
- ifp->ifindex, vni);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni,
+ add ? "ADD" : "DEL");
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- } else {
- /* process if-down for l2-vni */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name,
- ifp->ifindex, vni);
+ if (add) {
+ /* check if the vni is already present under zvrf */
+ if (zvrf->l3vni) {
+ snprintf(err, err_str_sz,
+ "VNI is already configured under the vrf");
+ return -1;
+ }
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
+ /* check if this VNI is already present in the system */
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+ snprintf(err, err_str_sz,
+ "VNI is already configured as L3-VNI");
return -1;
}
- assert(zevpn->vxlan_if == ifp);
+ /* Remove L2VNI if present */
+ zebra_vxlan_handle_vni_transition(zvrf, vni, add);
- /* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
- if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zevpn);
+ /* add the L3-VNI to the global table */
+ zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
- /* Delete this VNI from BGP. */
- zebra_evpn_send_del_to_client(zevpn);
+ /* associate the vrf with vni */
+ zvrf->l3vni = vni;
- /* Free up all neighbors and MACs, if any. */
- zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+ /* set the filter in l3vni to denote if we are using l3vni only
+ * for prefix routes
+ */
+ if (filter)
+ SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY);
- /* Free up all remote VTEPs, if any. */
- zebra_evpn_vtep_del_all(zevpn, 1);
- }
- return 0;
-}
+ /* associate with vxlan-intf;
+ * we need to associate with the vxlan-intf first
+ */
+ zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
-/*
- * Handle VxLAN interface up - update BGP if required.
- */
-int zebra_vxlan_if_up(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
- /* we need to associate with SVI, if any, we can associate with
- * svi-if only after association with vxlan-intf is complete
- */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s"
- , ifp->name, ifp->ifindex, vni,
- zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
- zl3vni->mac_vlan_if ?
- zl3vni->mac_vlan_if->name : "NIL");
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- } else {
- /* Handle L2-VNI add */
- struct interface *vlan_if = NULL;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name,
- ifp->ifindex, vni);
-
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
-
- assert(zevpn->vxlan_if == ifp);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- /* If part of a bridge, inform BGP about this VNI. */
- /* Also, read and populate local MACs and neighbors. */
- if (zif->brslave_info.br_if) {
- zebra_evpn_send_add_to_client(zevpn);
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- }
- }
-
- return 0;
-}
-
-/*
- * Handle VxLAN interface delete. Locate and remove entry in hash table
- * and update BGP, if required.
- */
-int zebra_vxlan_if_del(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name,
- ifp->ifindex);
-
- /* process oper-down for l3-vni */
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
-
- /* remove the association with vxlan_if */
- memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
- zl3vni->vxlan_if = NULL;
- } else {
-
- /* process if-del for l2-vni*/
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name,
- ifp->ifindex);
-
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return 0;
- }
-
- /* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
- if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zevpn);
- /* Delete VNI from BGP. */
- zebra_evpn_send_del_to_client(zevpn);
-
- /* Free up all neighbors and MAC, if any. */
- zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC);
-
- /* Free up all remote VTEPs, if any. */
- zebra_evpn_vtep_del_all(zevpn, 0);
-
- /* Delete the hash entry. */
- if (zebra_evpn_vxlan_del(zevpn)) {
- flog_err(EC_ZEBRA_VNI_DEL_FAILED,
- "Failed to del EVPN hash %p, IF %s(%u) VNI %u",
- zevpn, ifp->name, ifp->ifindex, zevpn->vni);
- return -1;
- }
- }
- return 0;
-}
-
-/*
- * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
- */
-int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
- struct interface *vlan_if = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex, chgflags);
-
- /* Removed from bridge? Cleanup and return */
- if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- return 0;
- }
-
- if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE)
- && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- return 0;
- }
-
- /* access-vlan change - process oper down, associate with new
- * svi_if and then process oper up again
- */
- if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- if (if_is_operative(ifp)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zl3vni->svi_if = NULL;
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
- zl3vni->mac_vlan_if =
- zl3vni_map_to_mac_vlan_if(zl3vni);
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(
- zl3vni);
- }
- }
-
- /*
- * local-ip change - process oper down, associate with new
- * local-ip and then process oper up again
- */
- if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) {
- if (if_is_operative(ifp)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(
- zl3vni);
- }
- }
-
- /* Update local tunnel IP. */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
-
- /* if we have a valid new master, process l3-vni oper up */
- if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
- if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- }
- } else {
-
- /* Update VNI hash. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to find EVPN hash on update, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex, chgflags);
-
- /* Removed from bridge? Cleanup and return */
- if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
- /* Delete from client, remove all remote VTEPs */
- /* Also, free up all MACs and neighbors. */
- zevpn->svi_if = NULL;
- zebra_evpn_send_del_to_client(zevpn);
- zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
- zebra_evpn_vtep_del_all(zevpn, 1);
- return 0;
- }
-
- /* Handle other changes. */
- if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- /* Remove all existing local neigh and MACs for this VNI
- * (including from BGP)
- */
- zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
- zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
- }
-
- if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES orig-ip
- * needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- /* Take further actions needed.
- * Note that if we are here, there is a change of interest.
- */
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return 0;
-
- /* Inform BGP, if there is a change of interest. */
- if (chgflags &
- (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE |
- ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE))
- zebra_evpn_send_add_to_client(zevpn);
-
- /* If there is a valid new master or a VLAN mapping change,
- * read and populate local MACs and neighbors.
- * Also, reinstall any remote MACs and neighbors
- * for this VNI (based on new VLAN).
- */
- if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- struct mac_walk_ctx m_wctx;
- struct neigh_walk_ctx n_wctx;
-
- zebra_evpn_read_mac_neigh(zevpn, ifp);
-
- memset(&m_wctx, 0, sizeof(m_wctx));
- m_wctx.zevpn = zevpn;
- hash_iterate(zevpn->mac_table,
- zebra_evpn_install_mac_hash, &m_wctx);
-
- memset(&n_wctx, 0, sizeof(n_wctx));
- n_wctx.zevpn = zevpn;
- hash_iterate(zevpn->neigh_table,
- zebra_evpn_install_neigh_hash, &n_wctx);
- }
- }
-
- return 0;
-}
-
-/*
- * Handle VxLAN interface add.
- */
-int zebra_vxlan_if_add(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- /* process if-add for l3-vni*/
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex);
-
- /* associate with vxlan_if */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- zl3vni->vxlan_if = ifp;
-
- /* Associate with SVI, if any. We can associate with svi-if only
- * after association with vxlan_if is complete */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
-
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- } else {
-
- /* process if-add for l2-vni */
- struct interface *vlan_if = NULL;
-
- /* Create or update EVPN hash. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn)
- zevpn = zebra_evpn_add(vni);
-
- if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES orig-ip
- * needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u",
- vni,
- vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME,
- ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip, &vxl->mcast_grp,
- zif->brslave_info.bridge_ifindex);
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return 0;
-
- /* Inform BGP */
- zebra_evpn_send_add_to_client(zevpn);
-
- /* Read and populate local MACs and neighbors */
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- }
-
- return 0;
-}
-
-int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
- char *err, int err_str_sz, int filter,
- int add)
-{
- struct zebra_l3vni *zl3vni = NULL;
- struct zebra_vrf *zvrf_evpn = NULL;
-
- zvrf_evpn = zebra_vrf_get_evpn();
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni,
- add ? "ADD" : "DEL");
-
- if (add) {
- /* check if the vni is already present under zvrf */
- if (zvrf->l3vni) {
- snprintf(err, err_str_sz,
- "VNI is already configured under the vrf");
- return -1;
- }
-
- /* check if this VNI is already present in the system */
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
- snprintf(err, err_str_sz,
- "VNI is already configured as L3-VNI");
- return -1;
- }
-
- /* Remove L2VNI if present */
- zebra_vxlan_handle_vni_transition(zvrf, vni, add);
-
- /* add the L3-VNI to the global table */
- zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
-
- /* associate the vrf with vni */
- zvrf->l3vni = vni;
-
- /* set the filter in l3vni to denote if we are using l3vni only
- * for prefix routes
- */
- if (filter)
- SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY);
-
- /* associate with vxlan-intf;
- * we need to associate with the vxlan-intf first
- */
- zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
-
- /* associate with corresponding SVI interface, we can associate
- * with svi-if only after vxlan interface association is
- * complete
- */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ /* associate with corresponding SVI interface, we can associate
+ * with svi-if only after vxlan interface association is
+ * complete
+ */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
} else {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni;
+ int old_advertise;
zevpn = zebra_evpn_lookup(vni);
if (!zevpn)
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "EVPN SVI macip Adv %s on VNI %d , currently %s",
+ "EVPN SVI macip Adv %s on VNI %d, currently %s",
advertise ? "enabled" : "disabled", vni,
advertise_svi_macip_enabled(zevpn)
? "enabled"
: "disabled");
- if (zevpn->advertise_svi_macip == advertise)
- return;
+ old_advertise = advertise_svi_macip_enabled(zevpn);
/* Store flag even though SVI is not present.
* Once SVI comes up triggers self MAC-IP route add.
*/
zevpn->advertise_svi_macip = advertise;
+ if (advertise_svi_macip_enabled(zevpn) == old_advertise)
+ return;
ifp = zevpn->vxlan_if;
if (!ifp)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
- vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
+
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
zif->brslave_info.br_if);
if (!vlan_if)
return;
struct zebra_evpn *zevpn = NULL;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni = NULL;
if (!EVPN_ENABLED(zvrf)) {
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
return;
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s",
+ zlog_debug("EVPN subnet Adv %s on VNI %d, currently %s",
advertise ? "enabled" : "disabled", vni,
zevpn->advertise_subnet ? "enabled" : "disabled");
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
+ zif->brslave_info.br_if);
if (!vlan_if)
return;
} else {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni = NULL;
+ int old_advertise;
zevpn = zebra_evpn_lookup(vni);
if (!zevpn)
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "EVPN gateway macip Adv %s on VNI %d , currently %s",
+ "EVPN gateway macip Adv %s on VNI %d, currently %s",
advertise ? "enabled" : "disabled", vni,
advertise_gw_macip_enabled(zevpn) ? "enabled"
- : "disabled");
+ : "disabled");
- if (zevpn->advertise_gw_macip == advertise)
- return;
+ old_advertise = advertise_gw_macip_enabled(zevpn);
zevpn->advertise_gw_macip = advertise;
+ if (advertise_gw_macip_enabled(zevpn) == old_advertise)
+ return;
ifp = zevpn->vxlan_if;
if (!ifp)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
- vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
zif->brslave_info.br_if);
if (!vlan_if)
return;
{
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
"Zebra VRF L3 VNI table");
+
+ svd_nh_table = zebra_neigh_db_create("Zebra SVD next-hop table");
+
zrouter.evpn_vrf = NULL;
zebra_evpn_mh_init();
}
return zl3vni->svi_if->ifindex;
}
+/* get the l3vni vxlan ifindex */
+ifindex_t get_l3vni_vxlan_ifindex(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return 0;
+
+ return zl3vni->vxlan_if->ifindex;
+}
+
+/* get the l3vni vni */
+vni_t get_l3vni_vni(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return 0;
+
+ return zl3vni->vni;
+}
+
+/* is the vrf l3vni SVD backed? */
+bool is_vrf_l3vni_svd_backed(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return false;
+
+ return IS_ZL3VNI_SVD_BACKED(zl3vni);
+}
+
/************************** vxlan SG cache management ************************/
/* Inform PIM about the mcast group */
static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
return vxlan_sg;
}
-static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp)
+void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp)
{
struct zebra_vrf *zvrf;
zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp);
}
-static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp)
+void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp)
{
struct zebra_vrf *zvrf;
return;
}
+/* Config knob for accepting lower sequence numbers */
+void zebra_vxlan_set_accept_bgp_seq(bool set)
+{
+ accept_bgp_seq = set;
+}
+
+bool zebra_vxlan_get_accept_bgp_seq(void)
+{
+ return accept_bgp_seq;
+}
+
/* Cleanup BGP EVPN configuration upon client disconnect */
extern void zebra_evpn_init(void)
{