summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/dplane_fpm_nl.c14
-rw-r--r--zebra/if_netlink.c365
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/interface.c170
-rw-r--r--zebra/interface.h1
-rw-r--r--zebra/kernel_netlink.c35
-rw-r--r--zebra/kernel_netlink.h4
-rw-r--r--zebra/redistribute.c6
-rw-r--r--zebra/rib.h3
-rw-r--r--zebra/rt.h5
-rw-r--r--zebra/rt_netlink.c282
-rw-r--r--zebra/rt_netlink.h5
-rw-r--r--zebra/rtread_netlink.c16
-rw-r--r--zebra/rtread_sysctl.c11
-rw-r--r--zebra/subdir.am4
-rw-r--r--zebra/zapi_msg.c12
-rw-r--r--zebra/zebra_dplane.c116
-rw-r--r--zebra/zebra_dplane.h36
-rw-r--r--zebra/zebra_evpn.c253
-rw-r--r--zebra/zebra_evpn.h17
-rw-r--r--zebra/zebra_evpn_mac.c28
-rw-r--r--zebra/zebra_evpn_mh.c229
-rw-r--r--zebra/zebra_evpn_mh.h18
-rw-r--r--zebra/zebra_evpn_neigh.c2
-rw-r--r--zebra/zebra_evpn_neigh.h3
-rw-r--r--zebra/zebra_evpn_vxlan.h30
-rw-r--r--zebra/zebra_l2.c81
-rw-r--r--zebra/zebra_l2.h79
-rw-r--r--zebra/zebra_l2_bridge_if.c383
-rw-r--r--zebra/zebra_l2_bridge_if.h75
-rw-r--r--zebra/zebra_mpls.c25
-rw-r--r--zebra/zebra_mpls.h4
-rw-r--r--zebra/zebra_nb_state.c20
-rw-r--r--zebra/zebra_nhg.c117
-rw-r--r--zebra/zebra_ns.c2
-rw-r--r--zebra/zebra_ptm.c1
-rw-r--r--zebra/zebra_rib.c104
-rw-r--r--zebra/zebra_rnh.c12
-rw-r--r--zebra/zebra_routemap.c28
-rw-r--r--zebra/zebra_vty.c76
-rw-r--r--zebra/zebra_vxlan.c1375
-rw-r--r--zebra/zebra_vxlan.h22
-rw-r--r--zebra/zebra_vxlan_if.c1162
-rw-r--r--zebra/zebra_vxlan_if.h96
-rw-r--r--zebra/zebra_vxlan_private.h16
45 files changed, 4086 insertions, 1260 deletions
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 0a9fecc9df..6a0f02bab4 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -45,9 +45,10 @@
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_router.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/debug.h"
@@ -1189,7 +1190,7 @@ static void fpm_enqueue_rmac_table(struct hash_bucket *bucket, void *arg)
struct fpm_rmac_arg *fra = arg;
struct zebra_mac *zrmac = bucket->data;
struct zebra_if *zif = fra->zl3vni->vxlan_if->info;
- const struct zebra_l2info_vxlan *vxl = &zif->l2info.vxl;
+ struct zebra_vxlan_vni *vni;
struct zebra_if *br_zif;
vlanid_t vid;
bool sticky;
@@ -1201,14 +1202,15 @@ static void fpm_enqueue_rmac_table(struct hash_bucket *bucket, void *arg)
sticky = !!CHECK_FLAG(zrmac->flags,
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
br_zif = (struct zebra_if *)(zif->brslave_info.br_if->info);
- vid = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) ? vxl->access_vlan : 0;
+ vni = zebra_vxlan_if_vni_find(zif, fra->zl3vni->vni);
+ vid = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) ? vni->access_vlan : 0;
dplane_ctx_reset(fra->ctx);
dplane_ctx_set_op(fra->ctx, DPLANE_OP_MAC_INSTALL);
dplane_mac_init(fra->ctx, fra->zl3vni->vxlan_if,
- zif->brslave_info.br_if, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, sticky,
- 0 /*nhg*/, 0 /*update_flags*/);
+ zif->brslave_info.br_if, vid, &zrmac->macaddr, vni->vni,
+ zrmac->fwd_info.r_vtep_ip, sticky, 0 /*nhg*/,
+ 0 /*update_flags*/);
if (fpm_nl_enqueue(fra->fnc, fra->ctx) == -1) {
thread_add_timer(zrouter.master, fpm_rmac_send,
fra->fnc, 1, &fra->fnc->t_rmacwalk);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 835659332b..6e5fef3b3f 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -544,7 +544,7 @@ static int netlink_extract_bridge_info(struct rtattr *link_data,
memset(bridge_info, 0, sizeof(*bridge_info));
netlink_parse_rtattr_nested(attr, IFLA_BR_MAX, link_data);
if (attr[IFLA_BR_VLAN_FILTERING])
- bridge_info->vlan_aware =
+ bridge_info->bridge.vlan_aware =
*(uint8_t *)RTA_DATA(attr[IFLA_BR_VLAN_FILTERING]);
return 0;
}
@@ -612,6 +612,7 @@ static int netlink_extract_gre_info(struct rtattr *link_data,
static int netlink_extract_vxlan_info(struct rtattr *link_data,
struct zebra_l2info_vxlan *vxl_info)
{
+ uint8_t svd = 0;
struct rtattr *attr[IFLA_VXLAN_MAX + 1];
vni_t vni_in_msg;
struct in_addr vtep_ip_in_msg;
@@ -619,15 +620,33 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
memset(vxl_info, 0, sizeof(*vxl_info));
netlink_parse_rtattr_nested(attr, IFLA_VXLAN_MAX, link_data);
- if (!attr[IFLA_VXLAN_ID]) {
+ if (attr[IFLA_VXLAN_COLLECT_METADATA]) {
+ svd = *(uint8_t *)RTA_DATA(attr[IFLA_VXLAN_COLLECT_METADATA]);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "IFLA_VXLAN_ID missing from VXLAN IF message");
- return -1;
+ "IFLA_VXLAN_COLLECT_METADATA=%u in VXLAN IF message",
+ svd);
+ }
+
+ if (!svd) {
+ /*
+ * In case of svd we will not get vni info directly from the
+ * device
+ */
+ if (!attr[IFLA_VXLAN_ID]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "IFLA_VXLAN_ID missing from VXLAN IF message");
+ return -1;
+ }
+
+ vxl_info->vni_info.iftype = ZEBRA_VXLAN_IF_VNI;
+ vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
+ vxl_info->vni_info.vni.vni = vni_in_msg;
+ } else {
+ vxl_info->vni_info.iftype = ZEBRA_VXLAN_IF_SVD;
}
- vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
- vxl_info->vni = vni_in_msg;
if (!attr[IFLA_VXLAN_LOCAL]) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
@@ -639,8 +658,10 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
}
if (attr[IFLA_VXLAN_GROUP]) {
- vxl_info->mcast_grp =
- *(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_GROUP]);
+ if (!svd)
+ vxl_info->vni_info.vni.mcast_grp =
+ *(struct in_addr *)RTA_DATA(
+ attr[IFLA_VXLAN_GROUP]);
}
if (!attr[IFLA_VXLAN_LINK]) {
@@ -701,16 +722,113 @@ static void netlink_interface_update_l2info(struct interface *ifp,
}
}
+static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp,
+ struct rtattr *af_spec)
+{
+ int rem;
+ vni_t vni_id;
+ vlanid_t vid;
+ uint16_t flags;
+ struct rtattr *i;
+ struct zebra_vxlan_vni vni;
+ struct zebra_vxlan_vni *vnip;
+ struct hash *vni_table = NULL;
+ struct zebra_vxlan_vni vni_end;
+ struct zebra_vxlan_vni vni_start;
+ struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+
+ for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); RTA_OK(i, rem);
+ i = RTA_NEXT(i, rem)) {
+
+ if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
+ continue;
+
+ memset(aftb, 0, sizeof(aftb));
+ netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
+ i);
+ if (!aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
+ !aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
+ /* vlan-vni info missing */
+ return 0;
+
+ flags = 0;
+ memset(&vni, 0, sizeof(vni));
+
+ vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
+ vni.access_vlan = *(vlanid_t *)RTA_DATA(
+ aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
+
+ if (aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
+ flags = *(uint16_t *)RTA_DATA(
+ aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
+
+ if (flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+ vni_start = vni;
+ continue;
+ }
+
+ if (flags & BRIDGE_VLAN_INFO_RANGE_END)
+ vni_end = vni;
+
+ if (!(flags & BRIDGE_VLAN_INFO_RANGE_END)) {
+ vni_start = vni;
+ vni_end = vni;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)",
+ vni_start.access_vlan, vni_end.access_vlan,
+ vni_start.vni, vni_end.vni, ifp->name,
+ ifp->ifindex);
+
+ if (!vni_table) {
+ vni_table = zebra_vxlan_vni_table_create();
+ if (!vni_table)
+ return 0;
+ }
+
+ for (vid = vni_start.access_vlan, vni_id = vni_start.vni;
+ vid <= vni_end.access_vlan; vid++, vni_id++) {
+
+ memset(&vni, 0, sizeof(vni));
+ vni.vni = vni_id;
+ vni.access_vlan = vid;
+ vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc);
+ if (!vnip)
+ return 0;
+ }
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+ }
+
+ if (vni_table)
+ zebra_vxlan_if_vni_table_add_update(ifp, vni_table);
+
+ return 0;
+}
+
static int netlink_bridge_vxlan_update(struct interface *ifp,
struct rtattr *af_spec)
{
struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
struct bridge_vlan_info *vinfo;
+ struct zebra_if *zif;
vlanid_t access_vlan;
if (!af_spec)
return 0;
+ zif = (struct zebra_if *)ifp->info;
+
+ /* Single vxlan devices has vni-vlan range to update */
+ if (IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return netlink_bridge_vxlan_vlan_vni_map_update(ifp, af_spec);
+
/* There is a 1-to-1 mapping of VLAN to VxLAN - hence
* only 1 access VLAN is accepted.
*/
@@ -2404,4 +2522,235 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
return 0;
}
+
+static const char *port_state2str(uint8_t state)
+{
+ switch (state) {
+ case BR_STATE_DISABLED:
+ return "DISABLED";
+ case BR_STATE_LISTENING:
+ return "LISTENING";
+ case BR_STATE_LEARNING:
+ return "LEARNING";
+ case BR_STATE_FORWARDING:
+ return "FORWARDING";
+ case BR_STATE_BLOCKING:
+ return "BLOCKING";
+ }
+
+ return "UNKNOWN";
+}
+
+static void vxlan_vni_state_change(struct zebra_if *zif, uint16_t id,
+ uint8_t state)
+{
+ struct zebra_vxlan_vni *vnip;
+
+ vnip = zebra_vxlan_if_vlanid_vni_find(zif, id);
+
+ if (!vnip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Cannot find VNI for VID (%u) IF %s for vlan state update",
+ id, zif->ifp->name);
+
+ return;
+ }
+
+ switch (state) {
+ case BR_STATE_FORWARDING:
+ zebra_vxlan_if_vni_up(zif->ifp, vnip);
+ break;
+ case BR_STATE_BLOCKING:
+ zebra_vxlan_if_vni_down(zif->ifp, vnip);
+ break;
+ case BR_STATE_DISABLED:
+ case BR_STATE_LISTENING:
+ case BR_STATE_LEARNING:
+ default:
+ /* Not used for anything at the moment */
+ break;
+ }
+}
+
+static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start,
+ uint16_t id_end, uint8_t state)
+{
+ struct zebra_if *zif;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!zif)
+ return;
+
+ for (uint16_t i = id_start; i <= id_end; i++)
+ vxlan_vni_state_change(zif, i, state);
+}
+
+/**
+ * netlink_vlan_change() - Read in change about vlans from the kernel
+ *
+ * @h: Netlink message header
+ * @ns_id: Namspace id
+ * @startup: Are we reading under startup conditions?
+ *
+ * Return: Result status
+ */
+int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
+{
+ int len, rem;
+ struct interface *ifp;
+ struct br_vlan_msg *bvm;
+ struct bridge_vlan_info *vinfo;
+ struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1] = {};
+ struct rtattr *attr;
+ uint8_t state;
+ uint32_t vrange;
+ int type;
+
+ /* We only care about state changes for now */
+ if (!(h->nlmsg_type == RTM_NEWVLAN))
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct br_vlan_msg));
+ if (len < 0) {
+ zlog_warn(
+ "%s: Message received from netlink is of a broken size %d %zu",
+ __func__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct br_vlan_msg)));
+ return -1;
+ }
+
+ bvm = NLMSG_DATA(h);
+
+ if (bvm->family != AF_BRIDGE)
+ return 0;
+
+ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), bvm->ifindex);
+ if (!ifp) {
+ zlog_debug("Cannot find bridge-vlan IF (%u) for vlan update",
+ bvm->ifindex);
+ return 0;
+ }
+
+ if (!IS_ZEBRA_IF_VXLAN(ifp)) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Ignoring non-vxlan IF (%s) for vlan update",
+ ifp->name);
+
+ return 0;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%s %s IF %s NS %u",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(bvm->family), ifp->name, ns_id);
+
+ /* Loop over "ALL" BRIDGE_VLANDB_ENTRY */
+ rem = len;
+ for (attr = BRVLAN_RTA(bvm); RTA_OK(attr, rem);
+ attr = RTA_NEXT(attr, rem)) {
+ vinfo = NULL;
+ vrange = 0;
+
+ type = attr->rta_type & NLA_TYPE_MASK;
+
+ if (type != BRIDGE_VLANDB_ENTRY)
+ continue;
+
+ /* Parse nested entry data */
+ netlink_parse_rtattr_nested(vtb, BRIDGE_VLANDB_ENTRY_MAX, attr);
+
+ /* It must have info for the ID */
+ if (!vtb[BRIDGE_VLANDB_ENTRY_INFO])
+ continue;
+
+ vinfo = (struct bridge_vlan_info *)RTA_DATA(
+ vtb[BRIDGE_VLANDB_ENTRY_INFO]);
+
+ /*
+ * We only care about state info, if there is none, just ignore
+ * it.
+ */
+ if (!vtb[BRIDGE_VLANDB_ENTRY_STATE])
+ continue;
+
+ state = *(uint8_t *)RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
+
+ if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
+ vrange = *(uint32_t *)RTA_DATA(
+ vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) {
+ if (vrange)
+ zlog_debug("VLANDB_ENTRY: VID (%u-%u) state=%s",
+ vinfo->vid, vrange,
+ port_state2str(state));
+ else
+ zlog_debug("VLANDB_ENTRY: VID (%u) state=%s",
+ vinfo->vid, port_state2str(state));
+ }
+
+ vlan_id_range_state_change(
+ ifp, vinfo->vid, (vrange ? vrange : vinfo->vid), state);
+ }
+
+ return 0;
+}
+
+/**
+ * netlink_request_vlan() - Request vlan information from the kernel
+ * @zns: Zebra namespace
+ * @family: AF_* netlink family
+ * @type: RTM_* type
+ *
+ * Return: Result status
+ */
+static int netlink_request_vlan(struct zebra_ns *zns, int family, int type)
+{
+ struct {
+ struct nlmsghdr n;
+ struct br_vlan_msg bvm;
+ char buf[256];
+ } req;
+
+ /* Form the request, specifying filter (rtattr) if needed. */
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = type;
+ req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg));
+ req.bvm.family = family;
+
+ nl_attr_put32(&req.n, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS,
+ BRIDGE_VLANDB_DUMPF_STATS);
+
+ return netlink_request(&zns->netlink_cmd, &req);
+}
+
+/**
+ * netlink_vlan_read() - Vlan read function using netlink interface
+ *
+ * @zns: Zebra name space
+ *
+ * Return: Result status
+ * Only called at bootstrap time.
+ */
+int netlink_vlan_read(struct zebra_ns *zns)
+{
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
+
+ /* Get bridg vlan info */
+ ret = netlink_request_vlan(zns, PF_BRIDGE, RTM_GETVLAN);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_vlan_change, &zns->netlink_cmd,
+ &dp_info, 0, 1);
+
+ return ret;
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index 21ae1713be..f215968657 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -40,6 +40,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
+extern int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
+extern int netlink_vlan_read(struct zebra_ns *zns);
+
extern ssize_t netlink_intf_msg_encode(uint16_t cmd,
const struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen);
diff --git a/zebra/interface.c b/zebra/interface.c
index a24f55dbba..5c60d355c2 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -229,6 +229,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
rtadv_if_fini(zebra_if);
+ zebra_l2_bridge_if_cleanup(ifp);
zebra_evpn_if_cleanup(zebra_if);
zebra_evpn_mac_ifp_del(ifp);
@@ -807,12 +808,12 @@ void if_delete_update(struct interface **pifp)
/* Reset some zebra interface params to default values. */
zif = ifp->info;
if (zif) {
+ zebra_evpn_if_cleanup(zif);
zif->zif_type = ZEBRA_IF_OTHER;
zif->zif_slave_type = ZEBRA_IF_SLAVE_NONE;
memset(&zif->l2info, 0, sizeof(union zebra_l2if_info));
memset(&zif->brslave_info, 0,
sizeof(struct zebra_l2info_brslave));
- zebra_evpn_if_cleanup(zif);
zebra_evpn_mac_ifp_del(ifp);
}
@@ -1890,6 +1891,63 @@ static inline bool if_is_protodown_applicable(struct interface *ifp)
return true;
}
+static void zebra_vxlan_if_vni_dump_vty(struct vty *vty,
+ struct zebra_vxlan_vni *vni)
+{
+ char str[INET6_ADDRSTRLEN];
+
+ vty_out(vty, " VxLAN Id %u", vni->vni);
+ if (vni->access_vlan)
+ vty_out(vty, " Access VLAN Id %u\n", vni->access_vlan);
+
+ if (vni->mcast_grp.s_addr != INADDR_ANY)
+ vty_out(vty, " Mcast Group %s",
+ inet_ntop(AF_INET, &vni->mcast_grp, str, sizeof(str)));
+}
+
+static void zebra_vxlan_if_vni_hash_dump_vty(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct vty *vty;
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ vty = (struct vty *)ctxt;
+
+ zebra_vxlan_if_vni_dump_vty(vty, vni);
+}
+
+static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if)
+{
+ struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vxlan_info = &zebra_if->l2info.vxl;
+ vni_info = &vxlan_info->vni_info;
+
+ if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
+ vty_out(vty, " VTEP IP: %pI4", &vxlan_info->vtep_ip);
+
+ if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(vxlan_info->link_nsid),
+ vxlan_info->ifindex_link);
+ vty_out(vty, " Link Interface %s",
+ ifp == NULL ? "Unknown" : ifp->name);
+ }
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) {
+ zebra_vxlan_if_vni_dump_vty(vty, &vni_info->vni);
+ } else {
+ hash_iterate(vni_info->vni_table,
+ zebra_vxlan_if_vni_hash_dump_vty, vty);
+ }
+
+ vty_out(vty, "\n");
+}
+
/* Interface's information print out to vty interface. */
static void if_dump_vty(struct vty *vty, struct interface *ifp)
{
@@ -1998,42 +2056,15 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
zebra_zifslavetype_2str(zebra_if->zif_slave_type));
if (IS_ZEBRA_IF_BRIDGE(ifp)) {
- struct zebra_l2info_bridge *bridge_info;
-
- bridge_info = &zebra_if->l2info.br;
vty_out(vty, " Bridge VLAN-aware: %s\n",
- bridge_info->vlan_aware ? "yes" : "no");
+ IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zebra_if) ? "yes" : "no");
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
vty_out(vty, " VLAN Id %u\n", vlan_info->vid);
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
- struct zebra_l2info_vxlan *vxlan_info;
-
- vxlan_info = &zebra_if->l2info.vxl;
- vty_out(vty, " VxLAN Id %u", vxlan_info->vni);
- if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
- vty_out(vty, " VTEP IP: %pI4",
- &vxlan_info->vtep_ip);
- if (vxlan_info->access_vlan)
- vty_out(vty, " Access VLAN Id %u\n",
- vxlan_info->access_vlan);
- if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
- vty_out(vty, " Mcast Group %pI4",
- &vxlan_info->mcast_grp);
- if (vxlan_info->ifindex_link &&
- (vxlan_info->link_nsid != NS_UNKNOWN)) {
- struct interface *ifp;
-
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(vxlan_info->link_nsid),
- vxlan_info->ifindex_link);
- vty_out(vty, " Link Interface %s",
- ifp == NULL ? "Unknown" :
- ifp->name);
- }
- vty_out(vty, "\n");
+ zebra_vxlan_if_dump_vty(vty, zebra_if);
} else if (IS_ZEBRA_IF_GRE(ifp)) {
struct zebra_l2info_gre *gre_info;
@@ -2226,6 +2257,59 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
#endif /* HAVE_NET_RT_IFLIST */
}
+static void zebra_vxlan_if_vni_dump_vty_json(json_object *json_if,
+ struct zebra_vxlan_vni *vni)
+{
+ json_object_int_add(json_if, "vxlanId", vni->vni);
+ if (vni->access_vlan)
+ json_object_int_add(json_if, "accessVlanId", vni->access_vlan);
+ if (vni->mcast_grp.s_addr != INADDR_ANY)
+ json_object_string_addf(json_if, "mcastGroup", "%pI4",
+ &vni->mcast_grp);
+}
+
+static void zebra_vxlan_if_vni_hash_dump_vty_json(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ json_object *json_if;
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ json_if = (json_object *)ctxt;
+
+ zebra_vxlan_if_vni_dump_vty_json(json_if, vni);
+}
+
+static void zebra_vxlan_if_dump_vty_json(json_object *json_if,
+ struct zebra_if *zebra_if)
+{
+ struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vxlan_info = &zebra_if->l2info.vxl;
+ vni_info = &vxlan_info->vni_info;
+
+ if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
+ json_object_string_addf(json_if, "vtepIp", "%pI4",
+ &vxlan_info->vtep_ip);
+
+ if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(vxlan_info->link_nsid),
+ vxlan_info->ifindex_link);
+ json_object_string_add(json_if, "linkInterface",
+ ifp == NULL ? "Unknown" : ifp->name);
+ }
+ if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) {
+ zebra_vxlan_if_vni_dump_vty_json(json_if, &vni_info->vni);
+ } else {
+ hash_iterate(vni_info->vni_table,
+ zebra_vxlan_if_vni_hash_dump_vty_json, json_if);
+ }
+}
+
static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
json_object *json)
{
@@ -2353,37 +2437,15 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
bridge_info = &zebra_if->l2info.br;
json_object_boolean_add(json_if, "bridgeVlanAware",
- bridge_info->vlan_aware);
+ bridge_info->bridge.vlan_aware);
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
json_object_int_add(json_if, "vlanId", vlan_info->vid);
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
- struct zebra_l2info_vxlan *vxlan_info;
-
- vxlan_info = &zebra_if->l2info.vxl;
- json_object_int_add(json_if, "vxlanId", vxlan_info->vni);
- if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
- json_object_string_addf(json_if, "vtepIp", "%pI4",
- &vxlan_info->vtep_ip);
- if (vxlan_info->access_vlan)
- json_object_int_add(json_if, "accessVlanId",
- vxlan_info->access_vlan);
- if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
- json_object_string_addf(json_if, "mcastGroup", "%pI4",
- &vxlan_info->mcast_grp);
- if (vxlan_info->ifindex_link
- && (vxlan_info->link_nsid != NS_UNKNOWN)) {
- struct interface *ifp;
+ zebra_vxlan_if_dump_vty_json(json_if, zebra_if);
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(vxlan_info->link_nsid),
- vxlan_info->ifindex_link);
- json_object_string_add(json_if, "linkInterface",
- ifp == NULL ? "Unknown"
- : ifp->name);
- }
} else if (IS_ZEBRA_IF_GRE(ifp)) {
struct zebra_l2info_gre *gre_info;
diff --git a/zebra/interface.h b/zebra/interface.h
index 8e39ca8c96..7e52990002 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -28,6 +28,7 @@
#include "bitfield.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_nhg_private.h"
#include "zebra/zebra_router.h"
#include "zebra/rtadv.h"
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 42afe61469..fac6acae0c 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -124,6 +124,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_NEWTFILTER, "RTM_NEWTFILTER"},
{RTM_DELTFILTER, "RTM_DELTFILTER"},
{RTM_GETTFILTER, "RTM_GETTFILTER"},
+ {RTM_NEWVLAN, "RTM_NEWVLAN"},
+ {RTM_DELVLAN, "RTM_DELVLAN"},
+ {RTM_GETVLAN, "RTM_GETVLAN"},
{0}};
static const struct message rtproto_str[] = {
@@ -432,6 +435,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
case RTM_NEWTFILTER:
case RTM_DELTFILTER:
return netlink_tfilter_change(h, ns_id, startup);
+ case RTM_NEWVLAN:
+ return netlink_vlan_change(h, ns_id, startup);
+ case RTM_DELVLAN:
+ return netlink_vlan_change(h, ns_id, startup);
/* Messages handled in the dplane thread */
case RTM_NEWADDR:
@@ -705,6 +712,12 @@ bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type,
return nl_attr_put(n, maxlen, type, &data, sizeof(uint32_t));
}
+bool nl_attr_put64(struct nlmsghdr *n, unsigned int maxlen, int type,
+ uint64_t data)
+{
+ return nl_attr_put(n, maxlen, type, &data, sizeof(uint64_t));
+}
+
struct rtattr *nl_attr_nest(struct nlmsghdr *n, unsigned int maxlen, int type)
{
struct rtattr *nest = NLMSG_TAIL(n);
@@ -1080,7 +1093,8 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
nl_msg_type_to_str(msg_type), msg_type,
err->msg.nlmsg_seq, err->msg.nlmsg_pid);
} else {
- if ((msg_type != RTM_GETNEXTHOP) || !startup)
+ if ((msg_type != RTM_GETNEXTHOP && msg_type != RTM_GETVLAN) ||
+ !startup)
flog_err(EC_ZEBRA_UNEXPECTED_MESSAGE,
"%s error: %s, type=%s(%u), seq=%u, pid=%u",
nl->name, safe_strerror(-errnum),
@@ -1761,7 +1775,7 @@ void kernel_init(struct zebra_ns *zns)
{
uint32_t groups, dplane_groups, ext_groups;
#if defined SOL_NETLINK
- int one, ret;
+ int one, ret, grp;
#endif
/*
@@ -1772,6 +1786,11 @@ void kernel_init(struct zebra_ns *zns)
* keeping track of all the different values would
* lead to confusion, so we need to convert the
* RTNLGRP_XXX to a bit position for ourself
+ *
+ *
+ * NOTE: If the bit is >= 32, you must use setsockopt(). Those
+ * groups are added further below after SOL_NETLINK is verified to
+ * exist.
*/
groups = RTMGRP_LINK |
RTMGRP_IPV4_ROUTE |
@@ -1851,6 +1870,18 @@ void kernel_init(struct zebra_ns *zns)
* sure that we want to pull into our build system.
*/
#if defined SOL_NETLINK
+
+ /*
+ * setsockopt multicast group subscriptions that don't fit in nl_groups
+ */
+ grp = RTNLGRP_BRVLAN;
+ ret = setsockopt(zns->netlink.sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+ &grp, sizeof(grp));
+
+ if (ret < 0)
+ zlog_notice(
+ "Registration for RTNLGRP_BRVLAN Membership failed : %d %s",
+ errno, safe_strerror(errno));
/*
* Let's tell the kernel that we want to receive extended
* ACKS over our command socket(s)
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 08cd706a9f..7d5453d544 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -31,7 +31,7 @@ extern "C" {
((struct rtattr *)(((char *)(h)) + NLMSG_ALIGN(sizeof(struct nhmsg))))
-#define NL_RCV_PKT_BUF_SIZE 32768
+#define NL_RCV_PKT_BUF_SIZE (34 * 1024)
#define NL_PKT_BUF_SIZE 8192
/*
@@ -48,6 +48,8 @@ extern bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type,
uint16_t data);
extern bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type,
uint32_t data);
+extern bool nl_attr_put64(struct nlmsghdr *n, unsigned int maxlen, int type,
+ uint64_t data);
/*
* nl_attr_nest - start an attribute nest.
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 4a8fe938ed..32d28f8002 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -118,13 +118,15 @@ static void zebra_redistribute(struct zserv *client, int type,
RNODE_FOREACH_RE (rn, newre) {
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s: client %s %pRN(%u:%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d",
+ "%s: client %s %pRN(%u:%u) checking: selected=%d, type=%s, instance=%u, distance=%d, metric=%d zebra_check_addr=%d",
__func__,
zebra_route_string(client->proto), rn,
vrf_id, newre->instance,
!!CHECK_FLAG(newre->flags,
ZEBRA_FLAG_SELECTED),
- newre->type, newre->distance,
+ zebra_route_string(newre->type),
+ newre->instance,
+ newre->distance,
newre->metric,
zebra_check_addr(&rn->p));
diff --git a/zebra/rib.h b/zebra/rib.h
index 166500fa5c..8a3b3e657f 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -625,6 +625,9 @@ extern pid_t pid;
extern bool v6_rr_semantics;
+/* Name of hook calls */
+#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/rt.h b/zebra/rt.h
index 6f4dd48a54..4ebf479754 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -103,7 +103,9 @@ extern void kernel_init(struct zebra_ns *zns);
extern void kernel_terminate(struct zebra_ns *zns, bool complete);
extern void macfdb_read(struct zebra_ns *zns);
extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if);
+ struct interface *br_if, vlanid_t vid);
+extern void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni);
extern void macfdb_read_specific_mac(struct zebra_ns *zns,
struct interface *br_if,
const struct ethaddr *mac, vlanid_t vid);
@@ -127,6 +129,7 @@ extern void kernel_update_multi(struct dplane_ctx_list_head *ctx_list);
* Called by the dplane pthread to read incoming OS messages and dispatch them.
*/
int kernel_dplane_read(struct zebra_dplane_info *info);
+extern void vlan_read(struct zebra_ns *zns);
#ifdef __cplusplus
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 216b719ff8..8bf59e02c7 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -153,6 +153,22 @@ static bool is_proto_nhg(uint32_t id, int type)
return false;
}
+/* Is vni mcast group */
+static bool is_mac_vni_mcast_group(struct ethaddr *mac, vni_t vni,
+ struct in_addr grp_addr)
+{
+ if (!vni)
+ return false;
+
+ if (!is_zero_mac(mac))
+ return false;
+
+ if (!IN_MULTICAST(ntohl(grp_addr.s_addr)))
+ return false;
+
+ return true;
+}
+
/*
* The ipv4_ll data structure is used for all 5549
* additions to the kernel. Let's figure out the
@@ -1309,6 +1325,7 @@ static bool _netlink_route_add_gateway_info(uint8_t route_family,
}
static int build_label_stack(struct mpls_label_stack *nh_label,
+ enum lsp_types_t nh_label_type,
mpls_lse_t *out_lse, char *label_buf,
size_t label_buf_size)
{
@@ -1316,7 +1333,8 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
int num_labels = 0;
for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+ if (nh_label_type != ZEBRA_LSP_EVPN &&
+ nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
continue;
if (IS_ZEBRA_DEBUG_KERNEL) {
@@ -1330,15 +1348,58 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
}
}
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+ if (nh_label_type == ZEBRA_LSP_EVPN)
+ out_lse[num_labels] = label2vni(&nh_label->label[i]);
+ else
+ out_lse[num_labels] =
+ mpls_lse_encode(nh_label->label[i], 0, 0, 0);
num_labels++;
}
return num_labels;
}
-static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
+static bool _netlink_nexthop_encode_dvni_label(const struct nexthop *nexthop,
+ struct nlmsghdr *nlmsg,
+ mpls_lse_t *out_lse,
+ size_t buflen, char *label_buf)
+{
+ struct in_addr ipv4;
+
+ if (!nl_attr_put64(nlmsg, buflen, LWTUNNEL_IP_ID,
+ htonll((uint64_t)out_lse[0])))
+ return false;
+
+ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST,
+ &nexthop->gate.ipv4, 4))
+ return false;
+
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
+ if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
+ ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, &ipv4);
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST, &ipv4,
+ 4))
+ return false;
+
+ } else {
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST,
+ &nexthop->gate.ipv6, 16))
+ return false;
+ }
+ } else {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s: nexthop %pNHv %s must NEXTHOP_TYPE_IPV*_IFINDEX to be vxlan encapped",
+ __func__, nexthop, label_buf);
+
+ return false;
+ }
+
+ return true;
+}
+
+static bool _netlink_route_encode_label_info(const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
size_t buflen, struct rtmsg *rtmsg,
char *label_buf,
@@ -1346,6 +1407,12 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
{
mpls_lse_t out_lse[MPLS_MAX_LABELS];
int num_labels;
+ struct rtattr *nest;
+ struct mpls_label_stack *nh_label;
+ enum lsp_types_t nh_label_type;
+
+ nh_label = nexthop->nh_label;
+ nh_label_type = nexthop->nh_label_type;
/*
* label_buf is *only* currently used within debugging.
@@ -1355,10 +1422,26 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
*/
label_buf[0] = '\0';
- num_labels =
- build_label_stack(nh_label, out_lse, label_buf, label_buf_size);
+ num_labels = build_label_stack(nh_label, nh_label_type, out_lse,
+ label_buf, label_buf_size);
+
+ if (num_labels && nh_label_type == ZEBRA_LSP_EVPN) {
+ if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
+ LWTUNNEL_ENCAP_IP))
+ return false;
+
+ nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP);
+ if (!nest)
+ return false;
+
+ if (_netlink_nexthop_encode_dvni_label(nexthop, nlmsg, out_lse,
+ buflen,
+ label_buf) == false)
+ return false;
- if (num_labels) {
+ nl_attr_nest_end(nlmsg, nest);
+
+ } else if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
@@ -1367,8 +1450,6 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
num_labels * sizeof(mpls_lse_t)))
return false;
} else {
- struct rtattr *nest;
-
if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
LWTUNNEL_ENCAP_MPLS))
return false;
@@ -1482,9 +1563,8 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
vrf = vrf_lookup_by_id(nexthop->vrf_id);
- if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
- req_size, rtmsg, label_buf,
- sizeof(label_buf)))
+ if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
+ label_buf, sizeof(label_buf)))
return false;
if (nexthop->nh_srv6) {
@@ -1765,9 +1845,8 @@ static bool _netlink_route_build_multipath(
vrf = vrf_lookup_by_id(nexthop->vrf_id);
- if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
- req_size, rtmsg, label_buf,
- sizeof(label_buf)))
+ if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
+ label_buf, sizeof(label_buf)))
return false;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
@@ -2649,11 +2728,28 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
req->nhm.nh_flags |= RTNH_F_ONLINK;
- num_labels =
- build_label_stack(nh->nh_label, out_lse,
- label_buf, sizeof(label_buf));
+ num_labels = build_label_stack(
+ nh->nh_label, nh->nh_label_type, out_lse,
+ label_buf, sizeof(label_buf));
- if (num_labels) {
+ if (num_labels && nh->nh_label_type == ZEBRA_LSP_EVPN) {
+ if (!nl_attr_put16(&req->n, buflen,
+ NHA_ENCAP_TYPE,
+ LWTUNNEL_ENCAP_IP))
+ return 0;
+
+ nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP);
+ if (!nest)
+ return 0;
+
+ if (_netlink_nexthop_encode_dvni_label(
+ nh, &req->n, out_lse, buflen,
+ label_buf) == false)
+ return 0;
+
+ nl_attr_nest_end(&req->n, nest);
+
+ } else if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |=
htonl(1 << MPLS_LS_S_SHIFT);
@@ -3400,17 +3496,32 @@ static ssize_t netlink_neigh_update_msg_encode(
if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
+ vni_t vni = dplane_ctx_mac_get_vni(ctx);
if (vid > 0) {
if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
return 0;
}
+ if (vni > 0) {
+ if (!nl_attr_put32(&req->n, datalen, NDA_SRC_VNI, vni))
+ return 0;
+ }
+
if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
dplane_ctx_mac_get_br_ifindex(ctx)))
return 0;
}
+ if (op == DPLANE_OP_VTEP_ADD || op == DPLANE_OP_VTEP_DELETE) {
+ vni_t vni = dplane_ctx_neigh_get_vni(ctx);
+
+ if (vni > 0) {
+ if (!nl_attr_put32(&req->n, datalen, NDA_SRC_VNI, vni))
+ return 0;
+ }
+ }
+
return NLMSG_ALIGN(req->n.nlmsg_len);
}
@@ -3457,7 +3568,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
bool sticky;
bool local_inactive = false;
bool dp_static = false;
+ vni_t vni = 0;
uint32_t nhg_id = 0;
+ bool vni_mcast_grp = false;
ndm = NLMSG_DATA(h);
@@ -3503,7 +3616,8 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
IPV4_MAX_BYTELEN);
snprintfrr(dst_buf, sizeof(dst_buf), " dst %pI4",
&vtep_ip);
- }
+ } else
+ memset(&vtep_ip, 0, sizeof(vtep_ip));
if (tb[NDA_NH_ID])
nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]);
@@ -3528,12 +3642,16 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
}
}
+ if (tb[NDA_SRC_VNI])
+ vni = *(vni_t *)RTA_DATA(tb[NDA_SRC_VNI]);
+
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d",
- nl_msg_type_to_str(h->nlmsg_type),
- ndm->ndm_ifindex, vid_present ? vid_buf : "",
- ndm->ndm_state, ndm->ndm_flags, &mac,
- dst_present ? dst_buf : "", nhg_id);
+ zlog_debug(
+ "Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d vni %d",
+ nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex,
+ vid_present ? vid_buf : "", ndm->ndm_state,
+ ndm->ndm_flags, &mac, dst_present ? dst_buf : "",
+ nhg_id, vni);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
@@ -3556,6 +3674,14 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
}
+ /* For per vni device, vni comes from device itself */
+ if (IS_ZEBRA_IF_VXLAN(ifp) && IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ struct zebra_vxlan_vni *vnip;
+
+ vnip = zebra_vxlan_if_vni_find(zif, 0);
+ vni = vnip->vni;
+ }
+
sticky = !!(ndm->ndm_flags & NTF_STICKY);
if (filter_vlan && vid != filter_vlan) {
@@ -3565,6 +3691,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
}
+ /*
+ * Check if this is a mcast group update (svd case)
+ */
+ vni_mcast_grp = is_mac_vni_mcast_group(&mac, vni, vtep_ip);
+
/* If add or update, do accordingly if learnt on a "local" interface; if
* the notification is over VxLAN, this has to be related to
* multi-homing,
@@ -3572,17 +3703,25 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
*/
if (h->nlmsg_type == RTM_NEWNEIGH) {
/* Drop "permanent" entries. */
- if (ndm->ndm_state & NUD_PERMANENT) {
+ if (!vni_mcast_grp && (ndm->ndm_state & NUD_PERMANENT)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
" Dropping entry because of NUD_PERMANENT");
return 0;
}
- if (IS_ZEBRA_IF_VXLAN(ifp))
+ if (IS_ZEBRA_IF_VXLAN(ifp)) {
+ if (!dst_present)
+ return 0;
+
+ if (vni_mcast_grp)
+ return zebra_vxlan_if_vni_mcast_group_add_update(
+ ifp, vni, &vtep_ip);
+
return zebra_vxlan_dp_network_mac_add(
- ifp, br_if, &mac, vid, nhg_id, sticky,
+ ifp, br_if, &mac, vid, vni, nhg_id, sticky,
!!(ndm->ndm_flags & NTF_EXT_LEARNED));
+ }
return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
sticky, local_inactive, dp_static);
@@ -3602,15 +3741,18 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
if (dst_present) {
- u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ if (vni_mcast_grp)
+ return zebra_vxlan_if_vni_mcast_group_del(ifp, vni,
+ &vtep_ip);
+
+ if (is_zero_mac(&mac) && vni)
+ return zebra_vxlan_check_readd_vtep(ifp, vni, vtep_ip);
- if (!memcmp(zero_mac, mac.octet, ETH_ALEN))
- return zebra_vxlan_check_readd_vtep(ifp, vtep_ip);
return 0;
}
if (IS_ZEBRA_IF_VXLAN(ifp))
- return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
+ return 0;
return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
}
@@ -3687,11 +3829,9 @@ int netlink_macfdb_read(struct zebra_ns *zns)
* specific bridge and matching specific access VLAN (if VLAN-aware bridge).
*/
int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
{
struct zebra_if *br_zif;
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
struct zebra_dplane_info dp_info;
int ret = 0;
@@ -3699,10 +3839,8 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
/* Save VLAN we're filtering on, if needed. */
br_zif = (struct zebra_if *)br_if->info;
- zif = (struct zebra_if *)ifp->info;
- vxl = &zif->l2info.vxl;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- filter_vlan = vxl->access_vlan;
+ filter_vlan = vid;
/* Get bridge FDB table for specific bridge - we do the VLAN filtering.
*/
@@ -3720,40 +3858,45 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
/* Request for MAC FDB for a specific MAC address in VLAN from the kernel */
-static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns,
- int family, int type,
- struct interface *br_if,
- const struct ethaddr *mac,
- vlanid_t vid)
+static int netlink_request_specific_mac(struct zebra_ns *zns, int family,
+ int type, struct interface *ifp,
+ const struct ethaddr *mac, vlanid_t vid,
+ vni_t vni, uint8_t flags)
{
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
- struct zebra_if *br_zif;
+ struct zebra_if *zif;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_type = type; /* RTM_GETNEIGH */
req.n.nlmsg_flags = NLM_F_REQUEST;
req.ndm.ndm_family = family; /* AF_BRIDGE */
+ req.ndm.ndm_flags = flags;
/* req.ndm.ndm_state = NUD_REACHABLE; */
nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
- br_zif = (struct zebra_if *)br_if->info;
- if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0)
- nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
-
- nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
+ zif = (struct zebra_if *)ifp->info;
+ /* Is this a read on a VXLAN interface? */
+ if (IS_ZEBRA_IF_VXLAN(ifp)) {
+ nl_attr_put32(&req.n, sizeof(req), NDA_VNI, vni);
+ /* TBD: Why is ifindex not filled in the non-vxlan case? */
+ req.ndm.ndm_ifindex = ifp->ifindex;
+ } else {
+ if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) && vid > 0)
+ nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
+ nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, ifp->ifindex);
+ }
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u",
- __func__, nl_family_to_str(req.ndm.ndm_family),
- br_if->name, br_if->ifindex, br_if->vrf->name,
- br_if->vrf->vrf_id, mac, vid);
+ zlog_debug("Tx %s %s IF %s(%u) MAC %pEA vid %u vni %u",
+ nl_msg_type_to_str(type),
+ nl_family_to_str(req.ndm.ndm_family), ifp->name,
+ ifp->ifindex, mac, vid, vni);
return netlink_request(&zns->netlink_cmd, &req);
}
@@ -3769,9 +3912,34 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
/* Get bridge FDB table for specific bridge - we do the VLAN filtering.
*/
- ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE,
- RTM_GETNEIGH,
- br_if, mac, vid);
+ ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, br_if,
+ mac, vid, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
+ &dp_info, 1, 0);
+
+ return ret;
+}
+
+int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
+{
+ struct zebra_if *zif;
+ struct ethaddr mac = {.octet = {0}};
+ struct zebra_dplane_info dp_info;
+ int ret = 0;
+
+ zif = ifp->info;
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif))
+ return 0;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
+
+ /* Get specific FDB entry for BUM handling, if any */
+ ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, ifp,
+ &mac, 0, vni, NTF_SELF);
if (ret < 0)
return ret;
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 8506367ae4..b550cc06b7 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -92,7 +92,10 @@ extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
extern int netlink_macfdb_read(struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns,
struct interface *ifp,
- struct interface *br_if);
+ struct interface *br_if,
+ vlanid_t vid);
+extern int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni);
extern int netlink_neigh_read(struct zebra_ns *zns);
extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns,
struct interface *vlan_if);
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 8990f66ef8..f9d4605562 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -28,6 +28,7 @@
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_tc.h"
#include "zebra/rt_netlink.h"
+#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
#include "zebra/tc_netlink.h"
@@ -42,9 +43,15 @@ void macfdb_read(struct zebra_ns *zns)
}
void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
{
- netlink_macfdb_read_for_bridge(zns, ifp, br_if);
+ netlink_macfdb_read_for_bridge(zns, ifp, br_if, vid);
+}
+
+void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
+{
+ netlink_macfdb_read_mcast_for_vni(zns, ifp, vni);
}
void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if,
@@ -78,4 +85,9 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
netlink_qdisc_read(zns);
}
+void vlan_read(struct zebra_ns *zns)
+{
+ netlink_vlan_read(zns);
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index 35dde0e686..f5b918c022 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -84,7 +84,12 @@ void macfdb_read(struct zebra_ns *zns)
}
void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
+{
+}
+
+void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
{
}
@@ -113,4 +118,8 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
{
}
+void vlan_read(struct zebra_ns *zns)
+{
+}
+
#endif /* !defined(GNU_LINUX) */
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 00f7d52994..1060e38785 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -67,6 +67,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_errors.c \
zebra/zebra_gr.c \
zebra/zebra_l2.c \
+ zebra/zebra_l2_bridge_if.c \
zebra/zebra_evpn.c \
zebra/zebra_evpn_mac.c \
zebra/zebra_evpn_neigh.c \
@@ -106,6 +107,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_vrf.c \
zebra/zebra_vty.c \
zebra/zebra_vxlan.c \
+ zebra/zebra_vxlan_if.c \
zebra/zebra_evpn_mh.c \
zebra/zebra_neigh.c \
zebra/zserv.c \
@@ -185,6 +187,8 @@ noinst_HEADERS += \
zebra/zebra_vxlan_private.h \
zebra/zebra_evpn_mh.h \
zebra/zebra_neigh.h \
+ zebra/zebra_l2_bridge_if.h \
+ zebra/zebra_vxlan_if.h \
zebra/zserv.h \
zebra/dpdk/zebra_dplane_dpdk.h \
zebra/dpdk/zebra_dplane_dpdk_private.h \
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index fdea766a1b..15b5790923 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1779,13 +1779,19 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
nexthop->srte_color = api_nh->srte_color;
}
- /* MPLS labels for BGP-LU or Segment Routing */
+ /* Labels for MPLS BGP-LU or Segment Routing or EVPN */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE
&& api_nh->label_num > 0) {
- label_type = lsp_type_from_re_type(client->proto);
+ /* If label type was passed, use it */
+ if (api_nh->label_type)
+ label_type = api_nh->label_type;
+ else
+ label_type =
+ lsp_type_from_re_type(client->proto);
+
nexthop_add_labels(nexthop, label_type,
api_nh->label_num,
&api_nh->labels[0]);
@@ -1823,7 +1829,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label,
labelbuf, sizeof(labelbuf),
- false);
+ nexthop->nh_label_type, false);
}
zlog_debug("%s: nh=%s, vrf_id=%d %s",
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index ef4cef65ca..dea5af44f8 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -222,6 +222,7 @@ struct dplane_mac_info {
vlanid_t vid;
ifindex_t br_ifindex;
struct ethaddr mac;
+ vni_t vni;
struct in_addr vtep_ip;
bool is_sticky;
uint32_t nhg_id;
@@ -237,6 +238,7 @@ struct dplane_neigh_info {
struct ethaddr mac;
struct ipaddr ip_addr;
} link;
+ vni_t vni;
uint32_t flags;
uint16_t state;
uint32_t update_flags;
@@ -628,17 +630,16 @@ static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
static enum zebra_dplane_result intf_addr_update_internal(
const struct interface *ifp, const struct connected *ifc,
enum dplane_op_e op);
-static enum zebra_dplane_result mac_update_common(
- enum dplane_op_e op, const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid, const struct ethaddr *mac,
- struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
- uint32_t update_flags);
+static enum zebra_dplane_result
+mac_update_common(enum dplane_op_e op, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, uint32_t update_flags);
static enum zebra_dplane_result
neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
const void *link, int link_family,
- const struct ipaddr *ip, uint32_t flags, uint16_t state,
- uint32_t update_flags, int protocol);
+ const struct ipaddr *ip, vni_t vni, uint32_t flags,
+ uint16_t state, uint32_t update_flags, int protocol);
/*
* Public APIs
@@ -2229,6 +2230,12 @@ const struct ethaddr *dplane_ctx_mac_get_addr(
return &(ctx->u.macinfo.mac);
}
+vni_t dplane_ctx_mac_get_vni(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.macinfo.vni;
+}
+
const struct in_addr *dplane_ctx_mac_get_vtep_ip(
const struct zebra_dplane_ctx *ctx)
{
@@ -2264,6 +2271,12 @@ const struct ethaddr *dplane_ctx_neigh_get_mac(
return &(ctx->u.neigh.link.mac);
}
+vni_t dplane_ctx_neigh_get_vni(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.neigh.vni;
+}
+
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -4649,14 +4662,11 @@ enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp)
/*
* Enqueue vxlan/evpn mac add (or update).
*/
-enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- bool was_static)
+enum zebra_dplane_result
+dplane_rem_mac_add(const struct interface *ifp,
+ const struct interface *bridge_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, bool was_static)
{
enum zebra_dplane_result result;
uint32_t update_flags = 0;
@@ -4666,8 +4676,9 @@ enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
update_flags |= DPLANE_MAC_WAS_STATIC;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky, nhg_id, update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, vid,
+ mac, vni, vtep_ip, sticky, nhg_id,
+ update_flags);
return result;
}
@@ -4675,10 +4686,10 @@ enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
* Enqueue vxlan/evpn mac delete.
*/
enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip)
+ const struct interface *bridge_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ vni_t vni, struct in_addr vtep_ip)
{
enum zebra_dplane_result result;
uint32_t update_flags = 0;
@@ -4686,8 +4697,8 @@ enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
update_flags |= DPLANE_MAC_REMOTE;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
- vid, mac, vtep_ip, false, 0, update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
+ mac, vni, vtep_ip, false, 0, update_flags);
return result;
}
@@ -4716,7 +4727,7 @@ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
update_flags = DPLANE_NEIGH_NO_EXTENSION;
result = neigh_update_internal(op, ifp, (const void *)link_ip,
- ipaddr_family(link_ip), ip, 0, state,
+ ipaddr_family(link_ip), ip, 0, 0, state,
update_flags, protocol);
return result;
@@ -4746,9 +4757,8 @@ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
vtep_ip.s_addr = 0;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky, 0,
- update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, vid,
+ mac, 0, vtep_ip, sticky, 0, update_flags);
return result;
}
@@ -4767,21 +4777,17 @@ dplane_local_mac_del(const struct interface *ifp,
/* Use common helper api */
result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
- mac, vtep_ip, false, 0, 0);
+ mac, 0, vtep_ip, false, 0, 0);
return result;
}
/*
* Public api to init an empty context - either newly-allocated or
* reset/cleared - for a MAC update.
*/
-void dplane_mac_init(struct zebra_dplane_ctx *ctx,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
+void dplane_mac_init(struct zebra_dplane_ctx *ctx, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni,
+ struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
uint32_t update_flags)
{
struct zebra_ns *zns;
@@ -4801,6 +4807,7 @@ void dplane_mac_init(struct zebra_dplane_ctx *ctx,
ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
ctx->u.macinfo.vtep_ip = vtep_ip;
ctx->u.macinfo.mac = *mac;
+ ctx->u.macinfo.vni = vni;
ctx->u.macinfo.vid = vid;
ctx->u.macinfo.is_sticky = sticky;
ctx->u.macinfo.nhg_id = nhg_id;
@@ -4811,15 +4818,10 @@ void dplane_mac_init(struct zebra_dplane_ctx *ctx,
* Common helper api for MAC address/vxlan updates
*/
static enum zebra_dplane_result
-mac_update_common(enum dplane_op_e op,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- uint32_t update_flags)
+mac_update_common(enum dplane_op_e op, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, uint32_t update_flags)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
@@ -4833,7 +4835,7 @@ mac_update_common(enum dplane_op_e op,
ctx->zd_op = op;
/* Common init for the ctx */
- dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky,
+ dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vni, vtep_ip, sticky,
nhg_id, update_flags);
/* Enqueue for processing on the dplane pthread */
@@ -4873,7 +4875,7 @@ enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
result = neigh_update_internal(
DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
- ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
+ ip, 0, flags, DPLANE_NUD_NOARP, update_flags, 0);
return result;
}
@@ -4906,8 +4908,8 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
ntf |= DPLANE_NTF_ROUTER;
result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
- (const void *)mac, AF_ETHERNET, ip, ntf,
- state, update_flags, 0);
+ (const void *)mac, AF_ETHERNET, ip, 0,
+ ntf, state, update_flags, 0);
return result;
}
@@ -4924,7 +4926,8 @@ enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
update_flags |= DPLANE_NEIGH_REMOTE;
result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
- AF_ETHERNET, ip, 0, 0, update_flags, 0);
+ AF_ETHERNET, ip, 0, 0, 0, update_flags,
+ 0);
return result;
}
@@ -4948,7 +4951,7 @@ enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
addr.ipaddr_v4 = *ip;
result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
- AF_ETHERNET, &addr, 0, 0, 0, 0);
+ AF_ETHERNET, &addr, vni, 0, 0, 0, 0);
return result;
}
@@ -4974,7 +4977,7 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
(const void *)&mac, AF_ETHERNET, &addr,
- 0, 0, 0, 0);
+ vni, 0, 0, 0, 0);
return result;
}
@@ -4985,7 +4988,7 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
enum zebra_dplane_result result;
result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
- AF_ETHERNET, ip, DPLANE_NTF_USE,
+ AF_ETHERNET, ip, 0, DPLANE_NTF_USE,
DPLANE_NUD_INCOMPLETE, 0, 0);
return result;
@@ -5053,8 +5056,8 @@ enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
static enum zebra_dplane_result
neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
const void *link, const int link_family,
- const struct ipaddr *ip, uint32_t flags, uint16_t state,
- uint32_t update_flags, int protocol)
+ const struct ipaddr *ip, vni_t vni, uint32_t flags,
+ uint16_t state, uint32_t update_flags, int protocol)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
@@ -5105,6 +5108,7 @@ neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
ctx->u.neigh.link.ip_addr = *link_ip;
ctx->u.neigh.flags = flags;
+ ctx->u.neigh.vni = vni;
ctx->u.neigh.state = state;
ctx->u.neigh.update_flags = update_flags;
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index ae13243a16..0c84992051 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -568,6 +568,7 @@ uint32_t dplane_ctx_mac_get_update_flags(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_mac_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_mac_get_addr(
const struct zebra_dplane_ctx *ctx);
+vni_t dplane_ctx_mac_get_vni(const struct zebra_dplane_ctx *ctx);
const struct in_addr *dplane_ctx_mac_get_vtep_ip(
const struct zebra_dplane_ctx *ctx);
ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx);
@@ -577,6 +578,7 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx);
+vni_t dplane_ctx_neigh_get_vni(const struct zebra_dplane_ctx *ctx);
const struct ipaddr *
dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx);
@@ -792,14 +794,11 @@ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
/*
* Enqueue evpn mac operations for the dataplane.
*/
-enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- bool was_static);
+enum zebra_dplane_result
+dplane_rem_mac_add(const struct interface *ifp,
+ const struct interface *bridge_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, bool was_static);
enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
const struct interface *bridge_ifp,
@@ -815,20 +814,17 @@ dplane_local_mac_del(const struct interface *ifp,
const struct ethaddr *mac);
enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip);
+ const struct interface *bridge_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ vni_t vni, struct in_addr vtep_ip);
/* Helper api to init an empty or new context for a MAC update */
-void dplane_mac_init(struct zebra_dplane_ctx *ctx,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id, uint32_t update_flags);
+void dplane_mac_init(struct zebra_dplane_ctx *ctx, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni,
+ struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
+ uint32_t update_flags);
/*
* Enqueue evpn neighbor updates for the dataplane.
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index ff9ca1ac25..bbe53adb2f 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -44,13 +44,14 @@
#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"
@@ -117,6 +118,9 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt)
if (json == NULL) {
vty_out(vty, "VNI: %u\n", zevpn->vni);
vty_out(vty, " Type: %s\n", "L2");
+ vty_out(vty, " Vlan: %u\n", zevpn->vid);
+ vty_out(vty, " Bridge: %s\n",
+ zevpn->bridge_if ? zevpn->bridge_if->name : "-");
vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zevpn->vrf_id));
} else {
json_object_int_add(json, "vni", zevpn->vni);
@@ -455,16 +459,16 @@ int zebra_evpn_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn,
{
struct zebra_mac *mac = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_vxlan_vni *vni;
zif = zevpn->vxlan_if->info;
if (!zif)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr,
- vxl->access_vlan, true);
+ vni->access_vlan, true);
return zebra_evpn_neigh_gw_macip_add(ifp, zevpn, ip, mac);
}
@@ -523,7 +527,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
+ struct zebra_vxlan_vni *vni = NULL;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
struct interface *ifp;
@@ -550,10 +554,11 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -573,10 +578,10 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
struct interface *ifp = NULL;
+ struct zebra_vxlan_vni *vni = NULL;
zevpn = (struct zebra_evpn *)bucket->data;
@@ -588,10 +593,11 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
/* If down or not mapped to a bridge, we're done. */
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -615,8 +621,8 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *vni = NULL;
struct interface *ifp;
/* Add primary SVI MAC*/
@@ -643,10 +649,11 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -660,6 +667,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
void *_in_param,
void **_p_zevpn)
{
+ int found = 0;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if;
@@ -667,42 +675,59 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl = NULL;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
+ vlanid_t vid;
+ vni_t vni_id = 0;
+ uint8_t bridge_vlan_aware;
assert(p_zevpn && in_param);
br_if = in_param->br_if;
+ assert(br_if);
zif = in_param->zif;
assert(zif);
- assert(br_if);
-
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- 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;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
+ vid = in_param->vid;
+ bridge_vlan_aware = in_param->bridge_vlan_aware;
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
- zevpn = zebra_evpn_lookup(vxl->vni);
- *p_zevpn = zevpn;
- return NS_WALK_STOP;
+ if (bridge_vlan_aware) {
+ vni_id = zebra_l2_bridge_if_vni_find(zif, vid);
+ if (vni_id)
+ found = 1;
+ } else {
+ /*
+ * See if this interface (or interface plus VLAN Id) maps to a
+ * VxLAN
+ */
+ /* TODO: Optimize with a hash. */
+ 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 (zif->brslave_info.br_if != br_if)
+ continue;
+
+ vni_id =
+ zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
- return NS_WALK_CONTINUE;
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ zevpn = zebra_evpn_lookup(vni_id);
+ *p_zevpn = zevpn;
+ return NS_WALK_STOP;
}
/*
@@ -713,7 +738,6 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
struct zebra_evpn **p_zevpn;
struct zebra_evpn *zevpn = NULL;
struct zebra_from_svi_param in_param;
@@ -721,8 +745,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
/* 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);
in_param.vid = vid;
in_param.br_if = br_if;
in_param.zif = zif;
@@ -745,43 +768,60 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_if *br_zif;
+ struct zebra_l2_bridge_vlan *bvlan;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
int found = 0;
+ vni_t vni_id = 0;
+ vlanid_t vid = 0;
+ uint8_t bridge_vlan_aware;
if (!in_param)
return NS_WALK_STOP;
+
br_if = in_param->br_if;
zif = in_param->zif;
assert(zif);
-
- /* TODO: Optimize with a hash. */
- 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;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
+ bridge_vlan_aware = in_param->bridge_vlan_aware;
+ vid = in_param->vid;
+ br_zif = br_if->info;
+ assert(br_zif);
+
+ if (bridge_vlan_aware) {
+ bvlan = zebra_l2_bridge_if_vlan_find(br_zif, vid);
+ if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) {
found = 1;
- break;
+ vni_id = bvlan->access_bd->vni;
+ }
+ } else {
+ /* TODO: Optimize with a hash. */
+ 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 (zif->brslave_info.br_if != br_if)
+ continue;
+
+ vni_id =
+ zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
if (!found)
return NS_WALK_CONTINUE;
- zevpn = zebra_evpn_lookup(vxl->vni);
+ zevpn = zebra_evpn_lookup(vni_id);
if (p_zevpn)
*p_zevpn = zevpn;
return NS_WALK_STOP;
@@ -794,7 +834,6 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if)
{
- struct zebra_l2info_bridge *br;
struct zebra_evpn *zevpn = NULL;
struct zebra_evpn **p_zevpn;
struct zebra_if *zif;
@@ -810,8 +849,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
/* 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);
in_param.vid = 0;
if (in_param.bridge_vlan_aware) {
@@ -906,9 +944,24 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
}
/*
+ * Uninstall MAC hash entry - called upon access VLAN change.
+ */
+static void zebra_evpn_uninstall_mac_hash(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_mac *mac;
+ struct mac_walk_ctx *wctx = ctxt;
+
+ mac = (struct zebra_mac *)bucket->data;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
+ zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false);
+}
+
+/*
* Install MAC hash entry - called upon access VLAN change.
*/
-void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
+static void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
{
struct zebra_mac *mac;
struct mac_walk_ctx *wctx = ctxt;
@@ -920,6 +973,44 @@ void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
}
/*
+ * Uninstall remote MAC entries for this EVPN.
+ */
+void zebra_evpn_rem_mac_uninstall_all(struct zebra_evpn *zevpn)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = 1;
+ wctx.upd_client = 0;
+ wctx.flags = ZEBRA_MAC_REMOTE;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_uninstall_mac_hash, &wctx);
+}
+
+/*
+ * Install remote MAC entries for this EVPN.
+ */
+void zebra_evpn_rem_mac_install_all(struct zebra_evpn *zevpn)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = 0;
+ wctx.upd_client = 0;
+ wctx.flags = ZEBRA_MAC_REMOTE;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_install_mac_hash, &wctx);
+}
+
+/*
* Read and populate local MACs and neighbors corresponding to this EVPN.
*/
void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
@@ -928,11 +1019,11 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
- struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni;
struct interface *vrr_if;
zif = ifp->info;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
zvrf = zebra_vrf_lookup_by_id(zevpn->vrf_id);
if (!zvrf || !zvrf->zns)
return;
@@ -944,8 +1035,13 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
ifp->name, ifp->ifindex, zevpn->vni,
zif->brslave_info.bridge_ifindex);
- macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if,
+ vni->access_vlan);
+ /* We need to specifically read and retrieve the entry for BUM handling
+ * via multicast, if any.
+ */
+ macfdb_read_mcast_entry_for_vni(zns, ifp, zevpn->vni);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (vlan_if) {
/* Add SVI MAC */
zebra_evpn_acc_bd_svi_mac_add(vlan_if);
@@ -1518,7 +1614,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
struct zebra_ns *zns;
- struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vnip;
struct zebra_vrf *zvrf;
char buf1[INET6_ADDRSTRLEN];
@@ -1541,7 +1637,14 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
return;
}
zns = zebra_ns_lookup(NS_DEFAULT);
- vxl = &zif->l2info.vxl;
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (!vnip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "VNI %u not in interface upon remote MACIP DEL",
+ vni);
+ return;
+ }
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (ipa_len)
@@ -1596,7 +1699,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
"%s: MAC %pEA (flags 0x%x) is remote and duplicate, read kernel for local entry",
__func__, macaddr, mac->flags);
macfdb_read_specific_mac(zns, zif->brslave_info.br_if,
- macaddr, vxl->access_vlan);
+ macaddr, vnip->access_vlan);
}
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
index 2c84d23045..8218b77213 100644
--- a/zebra/zebra_evpn.h
+++ b/zebra/zebra_evpn.h
@@ -33,6 +33,7 @@
#include "zebra/zebra_l2.h"
#include "zebra/interface.h"
+#include "zebra/zebra_vxlan.h"
#ifdef __cplusplus
extern "C" {
@@ -83,6 +84,10 @@ struct zebra_evpn {
uint32_t flags;
#define ZEVPN_READY_FOR_BGP (1 << 0) /* ready to be sent to BGP */
+ /* Corresponding Bridge information */
+ vlanid_t vid;
+ struct interface *bridge_if;
+
/* Flag for advertising gw macip */
uint8_t advertise_gw_macip;
@@ -138,7 +143,7 @@ static inline struct interface *zevpn_map_to_svi(struct zebra_evpn *zevpn)
{
struct interface *ifp;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
+ struct zebra_vxlan_vni *vni;
ifp = zevpn->vxlan_if;
if (!ifp)
@@ -146,12 +151,15 @@ static inline struct interface *zevpn_map_to_svi(struct zebra_evpn *zevpn)
zif = ifp->info;
if (!zif)
return NULL;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return NULL;
/* If down or not mapped to a bridge, we're done. */
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return NULL;
- zl2_info = zif->l2info.vxl;
- return zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+
+ return zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
}
int advertise_gw_macip_enabled(struct zebra_evpn *zevpn);
@@ -181,7 +189,8 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if);
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
struct interface *svi_if);
-void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_rem_mac_install_all(struct zebra_evpn *zevpn);
+void zebra_evpn_rem_mac_uninstall_all(struct zebra_evpn *zevpn);
void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp);
unsigned int zebra_evpn_hash_keymake(const void *p);
bool zebra_evpn_hash_cmp(const void *p1, const void *p2);
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 2c953eef15..801403c11c 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -36,6 +36,8 @@
#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_mac.h"
@@ -198,7 +200,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
bool was_static)
{
const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
+ const struct zebra_vxlan_vni *vni;
bool sticky;
enum zebra_dplane_result res;
const struct interface *br_ifp;
@@ -214,7 +216,9 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return -1;
sticky = !!CHECK_FLAG(mac->flags,
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
@@ -235,12 +239,12 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
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(zevpn->vxlan_if, br_ifp, vid, &mac->macaddr,
- vtep_ip, sticky, nhg_id, was_static);
+ vni->vni, vtep_ip, sticky, nhg_id, was_static);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -254,7 +258,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
struct zebra_mac *mac, bool force)
{
const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni;
struct in_addr vtep_ip;
const struct interface *ifp, *br_ifp;
vlanid_t vid;
@@ -280,19 +284,22 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return -1;
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;
ifp = zevpn->vxlan_if;
vtep_ip = mac->fwd_info.r_vtep_ip;
- res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
+ res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni,
+ vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -327,6 +334,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
struct interface **p_ifp,
vlanid_t *vid)
{
+ struct zebra_vxlan_vni *vni;
+
/* if the mac is associated with an ES we must get the access
* info from the ES
*/
@@ -338,7 +347,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
/* get the vlan from the EVPN */
if (mac->zevpn->vxlan_if) {
zif = mac->zevpn->vxlan_if->info;
- *vid = zif->l2info.vxl.access_vlan;
+ vni = zebra_vxlan_if_vni_find(zif, mac->zevpn->vni);
+ *vid = vni->access_vlan;
} else {
*vid = 0;
}
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 01ea9c5b9c..15def89e97 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -41,12 +41,13 @@
#include "zebra/if_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_vxlan_private.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_nhg.h"
@@ -481,6 +482,7 @@ void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
struct interface *vlan_if;
struct interface *vxlan_if;
struct zebra_if *vxlan_zif;
+ struct zebra_vxlan_vni *vni;
/* the EVPN is now elgible as a base for EVPN-MH */
if (zebra_evpn_send_to_client_ok(zevpn))
@@ -497,11 +499,15 @@ void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
vxlan_zif = vxlan_if->info;
if (if_is_operative(vxlan_if)
&& vxlan_zif->brslave_info.br_if) {
- vlan_if = zvni_map_to_svi(
- vxlan_zif->l2info.vxl.access_vlan,
- vxlan_zif->brslave_info.br_if);
- if (vlan_if)
- zebra_evpn_acc_bd_svi_mac_add(vlan_if);
+ vni = zebra_vxlan_if_vni_find(vxlan_zif, zevpn->vni);
+ /* VLAN-VNI mappings may not exist */
+ if (vni) {
+ vlan_if = zvni_map_to_svi(
+ vni->access_vlan,
+ vxlan_zif->brslave_info.br_if);
+ if (vlan_if)
+ zebra_evpn_acc_bd_svi_mac_add(vlan_if);
+ }
}
}
}
@@ -520,7 +526,7 @@ static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
{
const struct zebra_evpn_access_bd *acc_bd = p;
- return jhash_1word(acc_bd->vid, 0);
+ return jhash_2words(acc_bd->vid, acc_bd->bridge_ifindex, 0);
}
/* Compare two VLAN based broadcast domains */
@@ -535,16 +541,19 @@ static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
if (acc_bd1 == NULL || acc_bd2 == NULL)
return false;
- return (acc_bd1->vid == acc_bd2->vid);
+ return ((acc_bd1->vid == acc_bd2->vid) &&
+ (acc_bd1->bridge_ifindex == acc_bd2->bridge_ifindex));
}
/* Lookup VLAN based broadcast domain */
-static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
+struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid,
+ struct interface *br_if)
{
struct zebra_evpn_access_bd *acc_bd;
struct zebra_evpn_access_bd tmp;
tmp.vid = vid;
+ tmp.bridge_ifindex = br_if->ifindex;
acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
return acc_bd;
@@ -560,11 +569,13 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
struct interface *vlan_if;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d add", vid);
+ zlog_debug("access vlan %d bridge %s add", vid, br_if->name);
acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
acc_bd->vid = vid;
+ acc_bd->bridge_ifindex = br_if->ifindex;
+ acc_bd->bridge_zif = (struct zebra_if *)br_if->info;
/* Initialize the mbr list */
acc_bd->mbr_zifs = list_new();
@@ -573,14 +584,12 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
(void)hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern);
/* check if an svi exists for the vlan */
- if (br_if) {
- vlan_if = zvni_map_to_svi(vid, br_if);
- if (vlan_if) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI %s set", vid,
- vlan_if->name);
- acc_bd->vlan_zif = vlan_if->info;
- }
+ vlan_if = zvni_map_to_svi(vid, br_if);
+ if (vlan_if) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("vlan %d bridge %s SVI %s set", vid,
+ br_if->name, vlan_if->name);
+ acc_bd->vlan_zif = vlan_if->info;
}
return acc_bd;
}
@@ -621,16 +630,32 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
return;
+ /* Remove this access_bd from bridge hash table */
+ zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd);
+
/* if there are no references free the EVI */
zebra_evpn_acc_vl_free(acc_bd);
}
+static struct zebra_evpn_access_bd *
+zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid, struct interface *br_if)
+{
+ struct zebra_evpn_access_bd *acc_bd = NULL;
+
+ assert(br_if && br_if->info);
+ acc_bd = zebra_evpn_acc_vl_new(vid, br_if);
+ if (acc_bd)
+ /* Add this access_bd to bridge hash table */
+ zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd);
+
+ return acc_bd;
+}
+
/* called when a SVI is goes up/down */
void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
struct zebra_if *br_zif, bool is_up)
{
struct zebra_evpn_access_bd *acc_bd;
- struct zebra_l2info_bridge *br;
uint16_t vid;
struct zebra_if *tmp_br_zif = br_zif;
@@ -641,20 +666,19 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
tmp_br_zif = vlan_zif->link->info;
}
- br = &tmp_br_zif->l2info.br;
/* ignore vlan unaware bridges */
- if (!br->vlan_aware)
+ if (!IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(tmp_br_zif))
return;
vid = vlan_zif->l2info.vl.vid;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, tmp_br_zif->ifp);
if (!acc_bd)
return;
if (is_up) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI %s set", vid,
- vlan_zif->ifp->name);
+ zlog_debug("vlan %d bridge %s SVI %s set", vid,
+ tmp_br_zif->ifp->name, vlan_zif->ifp->name);
acc_bd->vlan_zif = vlan_zif;
if (acc_bd->zevpn)
@@ -662,7 +686,8 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
acc_bd->zevpn);
} else if (acc_bd->vlan_zif) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI clear", vid);
+ zlog_debug("vlan %d bridge %s SVI clear", vid,
+ tmp_br_zif->ifp->name);
acc_bd->vlan_zif = NULL;
if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
@@ -687,8 +712,9 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
struct listnode *node;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d l2-vni %u set",
- acc_bd->vid, zevpn ? zevpn->vni : 0);
+ zlog_debug("access vlan %d bridge %s l2-vni %u set",
+ acc_bd->vid, acc_bd->bridge_zif->ifp->name,
+ zevpn ? zevpn->vni : 0);
for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
if (!zif->es_info.es)
@@ -711,33 +737,44 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
}
/* handle VLAN->VxLAN_IF association */
-void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
+void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif)
{
+ vni_t old_vni;
struct zebra_evpn_access_bd *acc_bd;
- struct zebra_if *old_vxlan_zif;
struct zebra_evpn *old_zevpn;
+ struct interface *br_if;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ if (!vni_id)
+ return;
+
+ br_if = vxlan_zif->brslave_info.br_if;
+
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
- acc_bd = zebra_evpn_acc_vl_new(vid,
- vxlan_zif->brslave_info.br_if);
+ acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
- old_vxlan_zif = acc_bd->vxlan_zif;
- acc_bd->vxlan_zif = vxlan_zif;
- if (vxlan_zif == old_vxlan_zif)
+ old_vni = acc_bd->vni;
+
+ if (vni_id == old_vni)
return;
+ acc_bd->vni = vni_id;
+ acc_bd->vxlan_zif = vxlan_zif;
+
old_zevpn = acc_bd->zevpn;
- acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
+ acc_bd->zevpn = zebra_evpn_lookup(vni_id);
if (acc_bd->zevpn == old_zevpn)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d vni %u ref",
- acc_bd->vid, vxlan_zif->l2info.vxl.vni);
+ zlog_debug("access vlan %d vni %u ref", acc_bd->vid, vni_id);
if (old_zevpn)
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
@@ -747,30 +784,66 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
}
/* handle VLAN->VxLAN_IF deref */
-void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
+void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ if (!vni_id)
+ return;
+
+ br_if = vxlan_zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
return;
/* clear vxlan_if only if it matches */
- if (acc_bd->vxlan_zif != vxlan_zif)
+ if (acc_bd->vni != vni_id)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d vni %u deref",
- acc_bd->vid, vxlan_zif->l2info.vxl.vni);
+ zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd->vid,
+ br_if->name, vni_id);
if (acc_bd->zevpn)
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
acc_bd->zevpn = NULL;
acc_bd->vxlan_zif = NULL;
+ acc_bd->vni = 0;
+
+ /* if there are no other references the access_bd can be freed */
+ zebra_evpn_acc_bd_free_on_deref(acc_bd);
+}
+
+/* handle BridgeIf<->AccessBD cleanup */
+void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
+ struct zebra_evpn_access_bd *acc_bd)
+{
+ struct zebra_evpn *zevpn;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd->vid,
+ br_if->name);
+
+ zevpn = acc_bd->zevpn;
+ if (zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, zevpn);
+
+ /* cleanup resources maintained against the ES */
+ list_delete_all_node(acc_bd->mbr_zifs);
+
+ acc_bd->zevpn = NULL;
+ acc_bd->vxlan_zif = NULL;
+ acc_bd->vni = 0;
+ acc_bd->bridge_zif = NULL;
/* if there are no other references the access_bd can be freed */
zebra_evpn_acc_bd_free_on_deref(acc_bd);
@@ -780,15 +853,23 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
bool set)
{
- struct zebra_l2info_vxlan *vxl;
+ struct interface *br_if;
+ struct zebra_vxlan_vni *vni;
struct zebra_evpn_access_bd *acc_bd;
if (!zif)
return;
/* locate access_bd associated with the vxlan device */
- vxl = &zif->l2info.vxl;
- acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
+
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vni->access_vlan, br_if);
if (!acc_bd)
return;
@@ -810,21 +891,26 @@ void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
/* handle addition of new VLAN members */
void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
- acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
+ acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
if (listnode_lookup(acc_bd->mbr_zifs, zif))
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d mbr %s ref",
- vid, zif->ifp->name);
+ zlog_debug("access vlan %d bridge %s mbr %s ref", vid,
+ br_if->name, zif->ifp->name);
listnode_add(acc_bd->mbr_zifs, zif);
if (acc_bd->zevpn && zif->es_info.es)
@@ -834,13 +920,18 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
/* handle deletion of VLAN members */
void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
struct listnode *node;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
return;
@@ -849,8 +940,8 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d mbr %s deref",
- vid, zif->ifp->name);
+ zlog_debug("access vlan %d bridge %s mbr %s deref", vid,
+ br_if->name, zif->ifp->name);
list_delete_node(acc_bd->mbr_zifs, node);
@@ -917,14 +1008,19 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
if (json) {
zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
} else {
- vty_out(vty, "VLAN: %u\n", acc_bd->vid);
+ vty_out(vty, "VLAN: %s.%u\n", acc_bd->bridge_zif->ifp->name,
+ acc_bd->vid);
vty_out(vty, " VxLAN Interface: %s\n",
acc_bd->vxlan_zif ?
acc_bd->vxlan_zif->ifp->name : "-");
vty_out(vty, " SVI: %s\n",
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
- vty_out(vty, " L2-VNI: %d\n",
- acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
+ if (acc_bd->zevpn)
+ vty_out(vty, " L2-VNI: %d\n", acc_bd->zevpn->vni);
+ else {
+ vty_out(vty, " L2-VNI: 0\n");
+ vty_out(vty, " L3-VNI: %d\n", acc_bd->vni);
+ }
vty_out(vty, " Member Count: %d\n",
listcount(acc_bd->mbr_zifs));
vty_out(vty, " Members: \n");
@@ -940,7 +1036,8 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
if (json) {
zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
} else {
- vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
+ vty_out(vty, "%-5s.%-5u %-15s %-8d %-15s %u\n",
+ acc_bd->bridge_zif->ifp->name, acc_bd->vid,
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
@@ -978,7 +1075,7 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
wctx.detail = false;
if (!uj)
- vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
+ vty_out(vty, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
"L2-VNI", "VXLAN-IF", "# Members");
hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
@@ -1007,7 +1104,8 @@ void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
vty_json(vty, json_array);
}
-void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
+void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
+ struct interface *br_if)
{
json_object *json = NULL;
struct zebra_evpn_access_bd *acc_bd;
@@ -1015,12 +1113,13 @@ void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
if (uj)
json = json_object_new_object();
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (acc_bd) {
zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
} else {
if (!json)
- vty_out(vty, "VLAN %u not present\n", vid);
+ vty_out(vty, "VLAN %s.%u not present\n", br_if->name,
+ vid);
}
if (uj)
@@ -1977,7 +2076,7 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
return;
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, zif->brslave_info.br_if);
if (acc_bd->zevpn)
zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
}
@@ -1986,9 +2085,10 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
struct interface *ifp)
{
+ vlanid_t vid;
struct zebra_if *zif;
struct interface *br_ifp;
- vlanid_t vid;
+ struct zebra_vxlan_vni *vni;
zif = ifp->info;
br_ifp = zif->brslave_info.br_if;
@@ -1997,7 +2097,8 @@ static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
if (mac->zevpn->vxlan_if) {
zif = mac->zevpn->vxlan_if->info;
- vid = zif->l2info.vxl.access_vlan;
+ vni = zebra_vxlan_if_vni_find(zif, mac->zevpn->vni);
+ vid = vni->access_vlan;
} else {
vid = 0;
}
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 037648311c..12a8569504 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -179,6 +179,10 @@ struct zebra_evpn_es_vtep {
struct zebra_evpn_access_bd {
vlanid_t vid;
+ ifindex_t bridge_ifindex;
+ struct zebra_if *bridge_zif; /* associated bridge */
+
+ vni_t vni; /* vni associated with the vxlan device */
struct zebra_if *vxlan_zif; /* vxlan device */
/* list of members associated with the BD i.e. (potential) ESs */
struct list *mbr_zifs;
@@ -319,8 +323,10 @@ extern void zebra_evpn_vxl_evpn_set(struct zebra_if *zif,
struct zebra_evpn *zevpn, bool set);
extern void zebra_evpn_es_set_base_evpn(struct zebra_evpn *zevpn);
extern void zebra_evpn_es_clear_base_evpn(struct zebra_evpn *zevpn);
-extern void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif);
-extern void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif);
+extern void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif);
+extern void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif);
extern void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif);
extern void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif);
extern void zebra_evpn_es_send_all_to_client(bool add);
@@ -345,9 +351,12 @@ extern void zebra_evpn_interface_init(void);
extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp);
extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj);
extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj);
-extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid);
extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
struct zebra_if *zif);
+extern struct zebra_evpn_access_bd *
+zebra_evpn_acc_vl_find(vlanid_t vid, struct interface *br_if);
+extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
+ struct interface *br_if);
extern void zebra_evpn_es_cleanup(void);
extern int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
uint32_t duration, bool set_default);
@@ -373,6 +382,9 @@ extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj);
extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
struct zebra_if *br_zif, bool is_up);
extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if);
+extern void
+zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
+ struct zebra_evpn_access_bd *acc_bd);
extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es,
struct interface *ifp, bool bypass);
extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS);
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 684720bb4d..4c7f393fa1 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -36,6 +36,8 @@
#include "zebra/rt.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_neigh.h"
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
index 9271817440..6119cb8e72 100644
--- a/zebra/zebra_evpn_neigh.h
+++ b/zebra/zebra_evpn_neigh.h
@@ -63,6 +63,9 @@ struct zebra_neigh {
struct zebra_evpn *zevpn;
+ /* Refcnt - Only used by SVD neighs currently */
+ uint32_t refcnt;
+
uint32_t flags;
#define ZEBRA_NEIGH_LOCAL 0x01
#define ZEBRA_NEIGH_REMOTE 0x02
diff --git a/zebra/zebra_evpn_vxlan.h b/zebra/zebra_evpn_vxlan.h
index 3884a1e7ea..71df08a7a7 100644
--- a/zebra/zebra_evpn_vxlan.h
+++ b/zebra/zebra_evpn_vxlan.h
@@ -69,3 +69,33 @@ static inline void zevpn_vxlan_if_set(struct zebra_evpn *zevpn,
zebra_evpn_vxl_evpn_set(zif, zevpn, set);
}
+
+/* EVPN<=>Bridge interface association */
+static inline void zevpn_bridge_if_set(struct zebra_evpn *zevpn,
+ struct interface *ifp, bool set)
+{
+ if (set) {
+ if (zevpn->bridge_if == ifp)
+ return;
+ zevpn->bridge_if = ifp;
+ } else {
+ if (!zevpn->bridge_if)
+ return;
+ zevpn->bridge_if = NULL;
+ }
+}
+
+/* EVPN<=>Bridge interface association */
+static inline void zl3vni_bridge_if_set(struct zebra_l3vni *zl3vni,
+ struct interface *ifp, bool set)
+{
+ if (set) {
+ if (zl3vni->bridge_if == ifp)
+ return;
+ zl3vni->bridge_if = ifp;
+ } else {
+ if (!zl3vni->bridge_if)
+ return;
+ zl3vni->bridge_if = NULL;
+ }
+}
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index 8a9f3dffe3..c5d4c58852 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -42,7 +42,9 @@
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn_mh.h"
/* definitions */
@@ -262,12 +264,14 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
int add)
{
struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
zif = ifp->info;
assert(zif);
- /* Copy over the L2 information. */
- memcpy(&zif->l2info.br, bridge_info, sizeof(*bridge_info));
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ br->vlan_aware = bridge_info->bridge.vlan_aware;
+ zebra_l2_bridge_if_add(ifp);
/* Link all slaves to this bridge */
map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION);
@@ -278,6 +282,8 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
*/
void zebra_l2_bridge_del(struct interface *ifp)
{
+ zebra_l2_bridge_if_del(ifp);
+
/* Unlink all slaves to this bridge */
map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION);
}
@@ -341,34 +347,40 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info, int add)
{
struct zebra_if *zif;
- struct in_addr old_vtep_ip;
uint16_t chgflags = 0;
+ struct zebra_vxlan_if_update_ctx ctx;
zif = ifp->info;
assert(zif);
if (add) {
memcpy(&zif->l2info.vxl, vxlan_info, sizeof(*vxlan_info));
- zebra_evpn_vl_vxl_ref(zif->l2info.vxl.access_vlan, zif);
zebra_vxlan_if_add(ifp);
return;
}
- old_vtep_ip = zif->l2info.vxl.vtep_ip;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vtep_ip = zif->l2info.vxl.vtep_ip;
- if (!IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip)) {
+ if (!IPV4_ADDR_SAME(&ctx.old_vtep_ip, &vxlan_info->vtep_ip)) {
chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE;
zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
}
- if (!IPV4_ADDR_SAME(&zif->l2info.vxl.mcast_grp,
- &vxlan_info->mcast_grp)) {
- chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE;
- zif->l2info.vxl.mcast_grp = vxlan_info->mcast_grp;
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ ctx.old_vni = vxlan_info->vni_info.vni;
+ if (!IPV4_ADDR_SAME(&zif->l2info.vxl.vni_info.vni.mcast_grp,
+ &vxlan_info->vni_info.vni.mcast_grp)) {
+ chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+ zif->l2info.vxl.vni_info.vni.mcast_grp =
+ vxlan_info->vni_info.vni.mcast_grp;
+ }
}
- if (chgflags)
- zebra_vxlan_if_update(ifp, chgflags);
+ if (chgflags) {
+ ctx.chgflags = chgflags;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
}
/*
@@ -379,19 +391,30 @@ void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
{
struct zebra_if *zif;
vlanid_t old_access_vlan;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
zif = ifp->info;
assert(zif);
- old_access_vlan = zif->l2info.vxl.access_vlan;
+ /* This would be called only in non svd case */
+ assert(IS_ZEBRA_VXLAN_IF_VNI(zif));
+
+ old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan;
+ ;
if (old_access_vlan == access_vlan)
return;
- zif->l2info.vxl.access_vlan = access_vlan;
+ memset(&ctx, 0, sizeof(ctx));
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ ctx.old_vni = *vni;
+ ctx.chgflags = ZEBRA_VXLIF_VLAN_CHANGE;
+ vni->access_vlan = access_vlan;
- zebra_evpn_vl_vxl_deref(old_access_vlan, zif);
- zebra_evpn_vl_vxl_ref(zif->l2info.vxl.access_vlan, zif);
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_VLAN_CHANGE);
+ zebra_evpn_vl_vxl_deref(old_access_vlan, vni->vni, zif);
+ zebra_evpn_vl_vxl_ref(access_vlan, vni->vni, zif);
+ zebra_vxlan_if_update(ifp, &ctx);
}
/*
@@ -404,7 +427,6 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
zif = ifp->info;
assert(zif);
- zebra_evpn_vl_vxl_deref(zif->l2info.vxl.access_vlan, zif);
zebra_vxlan_if_del(ifp);
}
@@ -421,6 +443,9 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t old_bridge_ifindex;
ns_id_t old_ns_id;
struct zebra_vrf *zvrf;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
zif = ifp->info;
assert(zif);
@@ -431,11 +456,14 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
if (zif->zif_type == ZEBRA_IF_VXLAN
&& chgflags != ZEBRA_BRIDGE_NO_ACTION) {
- if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE)
- zebra_vxlan_if_update(ifp,
- ZEBRA_VXLIF_MASTER_MAC_CHANGE);
- if (chgflags & ZEBRA_BRIDGE_MASTER_UP)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) {
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_MAC_CHANGE;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
+ if (chgflags & ZEBRA_BRIDGE_MASTER_UP) {
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
}
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
old_ns_id = zif->brslave_info.ns_id;
@@ -443,6 +471,9 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
old_ns_id == zif->brslave_info.ns_id)
return;
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE;
+
+
zif->brslave_info.ns_id = ns_id;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
/* Set up or remove link with master */
@@ -450,7 +481,7 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ zebra_vxlan_if_update(ifp, &ctx);
if (zif->es_info.es)
zebra_evpn_es_local_br_port_update(zif);
} else if (old_bridge_ifindex != IFINDEX_INTERNAL) {
@@ -460,7 +491,7 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
* to unmapping the interface from the bridge.
*/
if (zif->zif_type == ZEBRA_IF_VXLAN)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ zebra_vxlan_if_update(ifp, &ctx);
if (zif->es_info.es)
zebra_evpn_es_local_br_port_update(zif);
zebra_l2_unmap_slave_from_bridge(&zif->brslave_info);
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index 1c3e98158d..e1ce13b163 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -49,9 +49,30 @@ struct zebra_l2info_bond {
struct list *mbr_zifs; /* slaves using this bond as a master */
};
+struct zebra_l2_bridge_vlan {
+ vlanid_t vid;
+ struct zebra_evpn_access_bd *access_bd;
+};
+
+struct zebra_l2_bridge_if_ctx {
+ /* input */
+ struct zebra_if *zif;
+ int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *vlan,
+ void *arg);
+
+ /* input-output */
+ void *arg;
+};
+
+struct zebra_l2_bridge_if {
+ uint8_t vlan_aware;
+ struct zebra_if *br_zif;
+ struct hash *vlan_table;
+};
+
/* zebra L2 interface information - bridge interface */
struct zebra_l2info_bridge {
- uint8_t vlan_aware; /* VLAN-aware bridge? */
+ struct zebra_l2_bridge_if bridge;
};
/* zebra L2 interface information - VLAN interface */
@@ -71,12 +92,52 @@ struct zebra_l2info_gre {
ns_id_t link_nsid;
};
+struct zebra_vxlan_vni {
+ vni_t vni; /* VNI */
+ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
+ struct in_addr mcast_grp;
+};
+
+enum {
+ ZEBRA_VXLAN_IF_VNI = 0, /* per vni vxlan if */
+ ZEBRA_VXLAN_IF_SVD /* single vxlan device */
+};
+
+struct zebra_vxlan_if_vlan_ctx {
+ vlanid_t vid;
+ struct zebra_vxlan_vni *vni;
+};
+
+struct zebra_vxlan_if_update_ctx {
+ uint16_t chgflags;
+ struct in_addr old_vtep_ip;
+ struct zebra_vxlan_vni old_vni;
+ struct hash *old_vni_table;
+};
+
+struct zebra_vxlan_if_ctx {
+ /* input */
+ struct zebra_if *zif;
+ int (*func)(struct zebra_if *zif, struct zebra_vxlan_vni *vni,
+ void *arg);
+
+ /* input-output */
+ void *arg;
+};
+
+struct zebra_vxlan_vni_info {
+ int iftype;
+ union {
+ struct zebra_vxlan_vni vni; /* per vni vxlan device vni info */
+ struct hash
+ *vni_table; /* table of vni's assocated with this if */
+ };
+};
+
/* zebra L2 interface information - VXLAN interface */
struct zebra_l2info_vxlan {
- vni_t vni; /* VNI */
+ struct zebra_vxlan_vni_info vni_info;
struct in_addr vtep_ip; /* Local tunnel IP */
- vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
- struct in_addr mcast_grp;
ifindex_t ifindex_link; /* Interface index of interface
* linked with VXLAN
*/
@@ -99,10 +160,16 @@ union zebra_l2if_info {
* IOW, the macro VNI_FROM_ZEBRA_IF() will assume the interface is
* of type ZEBRA_IF_VXLAN.
*/
-#define VNI_FROM_ZEBRA_IF(zif) (zif)->l2info.vxl.vni
+#define VNI_INFO_FROM_ZEBRA_IF(zif) (&((zif)->l2info.vxl.vni_info))
+#define IS_ZEBRA_VXLAN_IF_SVD(zif) \
+ ((zif)->l2info.vxl.vni_info.iftype == ZEBRA_VXLAN_IF_SVD)
+#define IS_ZEBRA_VXLAN_IF_VNI(zif) \
+ ((zif)->l2info.vxl.vni_info.iftype == ZEBRA_VXLAN_IF_VNI)
#define VLAN_ID_FROM_ZEBRA_IF(zif) (zif)->l2info.vl.vid
-#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) ((zif)->l2info.br.vlan_aware == 1)
+#define BRIDGE_FROM_ZEBRA_IF(zif) (&((zif)->l2info.br.bridge))
+#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) \
+ ((zif)->l2info.br.bridge.vlan_aware == 1)
extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
struct zebra_ns *zns);
diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c
new file mode 100644
index 0000000000..6574899927
--- /dev/null
+++ b/zebra/zebra_l2_bridge_if.c
@@ -0,0 +1,383 @@
+/*
+ * Zebra L2 bridge interface handling
+ *
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+#include "vlan.h"
+#include "vxlan.h"
+#ifdef GNU_LINUX
+#include <linux/neighbour.h>
+#endif
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.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_if.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"
+
+static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p)
+{
+ const struct zebra_l2_bridge_vlan *bvlan;
+
+ bvlan = (const struct zebra_l2_bridge_vlan *)p;
+ return jhash(&bvlan->vid, sizeof(bvlan->vid), 0);
+}
+
+static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2)
+{
+ const struct zebra_l2_bridge_vlan *bv1;
+ const struct zebra_l2_bridge_vlan *bv2;
+
+ bv1 = (const struct zebra_l2_bridge_vlan *)p1;
+ bv2 = (const struct zebra_l2_bridge_vlan *)p2;
+
+ return (bv1->vid == bv2->vid);
+}
+
+static int zebra_l2_bridge_if_vlan_walk_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ int ret;
+ struct zebra_l2_bridge_vlan *bvlan;
+ struct zebra_l2_bridge_if_ctx *ctx;
+
+ bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
+ ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
+
+ ret = ctx->func(ctx->zif, bvlan, ctx->arg);
+ return ret;
+}
+
+static void zebra_l2_bridge_if_vlan_iterate_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_l2_bridge_vlan *bvlan;
+ struct zebra_l2_bridge_if_ctx *ctx;
+
+ bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
+ ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
+
+ ctx->func(ctx->zif, bvlan, ctx->arg);
+}
+
+static int zebra_l2_bridge_if_vlan_clean(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *bvlan,
+ void *ctxt)
+{
+ struct zebra_evpn_access_bd *acc_bd;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("access vlan %d bridge %s cleanup", bvlan->vid,
+ zif->ifp->name);
+
+ acc_bd = zebra_evpn_acc_vl_find(bvlan->vid, zif->ifp);
+ if (acc_bd)
+ zebra_evpn_access_bd_bridge_cleanup(bvlan->vid, zif->ifp,
+ acc_bd);
+
+ bvlan->access_bd = NULL;
+ return 0;
+}
+
+static void zebra_l2_bridge_vlan_free(void *arg)
+{
+ struct zebra_l2_bridge_vlan *bvl;
+
+ bvl = (struct zebra_l2_bridge_vlan *)arg;
+ XFREE(MTYPE_TMP, bvl);
+}
+
+static void *zebra_l2_bridge_vlan_alloc(void *p)
+{
+ struct zebra_l2_bridge_vlan *bvlan;
+ const struct zebra_l2_bridge_vlan *bvl;
+
+ bvl = (const struct zebra_l2_bridge_vlan *)p;
+ bvlan = XCALLOC(MTYPE_TMP, sizeof(*bvlan));
+ bvlan->vid = bvl->vid;
+ bvlan->access_bd = bvl->access_bd;
+
+ return (void *)bvlan;
+}
+
+static void zebra_l2_bridge_vlan_table_destroy(struct hash *vlan_table)
+{
+ if (vlan_table) {
+ hash_clean(vlan_table, zebra_l2_bridge_vlan_free);
+ hash_free(vlan_table);
+ }
+}
+
+static struct hash *zebra_l2_bridge_vlan_table_create(void)
+{
+ return hash_create(zebra_l2_bridge_vlan_hash_keymake,
+ zebra_l2_bridge_vlan_hash_cmp,
+ "Zebra L2 Bridge Vlan Table");
+}
+
+static void zebra_l2_bridge_if_vlan_table_destroy(struct zebra_if *zif)
+{
+ struct zebra_l2_bridge_if *br;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ zebra_l2_bridge_if_vlan_iterate(zif, zebra_l2_bridge_if_vlan_clean,
+ NULL);
+ zebra_l2_bridge_vlan_table_destroy(br->vlan_table);
+ br->vlan_table = NULL;
+}
+
+static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif)
+{
+ struct zebra_l2_bridge_if *br;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ if (!br->vlan_table) {
+ br->vlan_table = zebra_l2_bridge_vlan_table_create();
+ if (!br->vlan_table)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_del(struct interface *ifp, vlanid_t vid)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = (struct zebra_if *)ifp->info;
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = vid;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ bvlan = hash_release(br->vlan_table, &bvl);
+
+ if (bvlan)
+ zebra_l2_bridge_vlan_free(bvlan);
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_update(struct interface *ifp,
+ struct zebra_l2_bridge_vlan *bvl,
+ int chgflags)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = (struct zebra_if *)ifp->info;
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bvl->vid);
+
+ if (chgflags & ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE)
+ bvlan->access_bd = bvl->access_bd;
+
+ if (!bvlan->access_bd)
+ return zebra_l2_bridge_if_vlan_del(ifp, bvl->vid);
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_add(struct interface *ifp,
+ struct zebra_l2_bridge_vlan *bvlan)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+
+ zif = (struct zebra_if *)ifp->info;
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ hash_get(br->vlan_table, (void *)bvlan, zebra_l2_bridge_vlan_alloc);
+
+ return 0;
+}
+
+struct zebra_l2_bridge_vlan *
+zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid)
+{
+ const struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_vlan *bvl;
+ struct zebra_l2_bridge_vlan bvlan;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&bvlan, 0, sizeof(bvlan));
+ bvlan.vid = vid;
+ bvl = (struct zebra_l2_bridge_vlan *)hash_lookup(br->vlan_table,
+ (void *)&bvlan);
+
+ /* TODO: For debugging. Remove later */
+ if (bvl)
+ assert(bvl->vid == vid);
+
+ return bvl;
+}
+
+vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif, vlanid_t vid)
+{
+ vni_t vni_id = 0;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, vid);
+ if (bvlan && bvlan->access_bd && bvlan->access_bd->vni)
+ vni_id = bvlan->access_bd->vni;
+
+ return vni_id;
+}
+
+void zebra_l2_bridge_if_vlan_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg)
+{
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_if_ctx ctx;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_iterate(br->vlan_table, zebra_l2_bridge_if_vlan_iterate_callback,
+ &ctx);
+}
+
+void zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg)
+{
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_if_ctx ctx;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_walk(br->vlan_table, zebra_l2_bridge_if_vlan_walk_callback, &ctx);
+}
+
+int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd)
+{
+ int chgflags = 0;
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = bd->bridge_zif;
+ if (!zif)
+ return -1;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
+ if (!bvlan)
+ return 0;
+
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = bd->vid;
+ bvl.access_bd = NULL;
+ chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
+ return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
+}
+
+int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd)
+{
+ int chgflags = 0;
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = bd->bridge_zif;
+ if (!zif)
+ return -1;
+
+ if (!bd->vid)
+ return -1;
+
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = bd->vid;
+ bvl.access_bd = bd;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
+ if (!bvlan)
+ return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl);
+
+ chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
+ return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
+}
+
+int zebra_l2_bridge_if_cleanup(struct interface *ifp)
+{
+ struct zebra_if *zif;
+
+ if (!IS_ZEBRA_IF_BRIDGE(ifp))
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("bridge %s cleanup", ifp->name);
+
+ zif = (struct zebra_if *)ifp->info;
+ zebra_l2_bridge_if_vlan_table_destroy(zif);
+ return 0;
+}
+
+int zebra_l2_bridge_if_del(struct interface *ifp)
+{
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("bridge %s delete", ifp->name);
+
+ return zebra_l2_bridge_if_cleanup(ifp);
+}
+
+int zebra_l2_bridge_if_add(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+
+ zif = (struct zebra_if *)ifp->info;
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ br->br_zif = (struct zebra_if *)ifp->info;
+ zebra_l2_bridge_if_vlan_table_create(zif);
+ return 0;
+}
diff --git a/zebra/zebra_l2_bridge_if.h b/zebra/zebra_l2_bridge_if.h
new file mode 100644
index 0000000000..734ecfdcf1
--- /dev/null
+++ b/zebra/zebra_l2_bridge_if.h
@@ -0,0 +1,75 @@
+/*
+ * Zebra L2 bridge interface data structures and definitions
+ * These are public definitions referenced by other files.
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_L2_BRIDGE_IF_H
+#define _ZEBRA_L2_BRIDGE_IF_H
+
+#include <zebra.h>
+#include <zebra/zebra_router.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "lib/json.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zserv.h"
+
+#include "zebra/zebra_dplane.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Bridge interface change flags of interest. */
+#define ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE (1 << 0)
+
+extern struct zebra_l2_bridge_vlan *
+zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid);
+extern vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif,
+ vlanid_t vid);
+extern void zebra_l2_bridge_if_vlan_iterate(
+ struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg);
+extern void
+zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *, void *),
+ void *arg);
+extern int
+zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd);
+extern int
+zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd);
+extern int zebra_l2_bridge_if_del(struct interface *ifp);
+extern int zebra_l2_bridge_if_add(struct interface *ifp);
+extern int zebra_l2_bridge_if_cleanup(struct interface *ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_L2_BRIDGE_IF_H */
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 13963d9cc3..aec4961126 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -492,7 +492,7 @@ static void fec_print(struct zebra_fec *fec, struct vty *vty)
rn = fec->rn;
vty_out(vty, "%pRN\n", rn);
- vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
+ vty_out(vty, " Label: %s", label2str(fec->label, 0, buf, BUFSIZ));
if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
vty_out(vty, ", Label Index: %u", fec->label_index);
vty_out(vty, "\n");
@@ -1597,8 +1597,8 @@ static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
vty_out(vty, " type: %s remote label: %s distance: %d\n",
nhlfe_type2str(nhlfe->type),
mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label,
- buf, sizeof(buf), 0),
+ nexthop->nh_label->label, buf, sizeof(buf),
+ nexthop->nh_label_type, 0),
nhlfe->distance);
if (indent)
@@ -2719,7 +2719,7 @@ int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
write = 1;
vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
- label2str(fec->label, lstr, BUFSIZ));
+ label2str(fec->label, 0, lstr, BUFSIZ));
}
}
@@ -3164,10 +3164,10 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
nhlfe2str(nhlfe, buf, sizeof(buf));
mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
+ sizeof(buf2), 0, 0);
mpls_label2str(nh->nh_label->num_labels,
nh->nh_label->label, buf3, sizeof(buf3),
- 0);
+ nh->nh_label_type, 0);
zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
lsp->ile.in_label, type, backup_str, buf,
@@ -3195,7 +3195,7 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
nhlfe2str(nhlfe, buf, sizeof(buf));
mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
+ sizeof(buf2), 0, 0);
zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
lsp->ile.in_label, type, backup_str, buf,
@@ -3778,10 +3778,10 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
json = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
- json_object_object_add(
- json, label2str(lsp->ile.in_label, buf,
- sizeof(buf)),
- lsp_json(lsp));
+ json_object_object_add(json,
+ label2str(lsp->ile.in_label, 0,
+ buf, sizeof(buf)),
+ lsp_json(lsp));
vty_json(vty, json);
} else {
@@ -3833,7 +3833,8 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
out_label_str = mpls_label2str(
nexthop->nh_label->num_labels,
&nexthop->nh_label->label[0],
- buf, sizeof(buf), 1);
+ buf, sizeof(buf),
+ nexthop->nh_label_type, 1);
else
out_label_str = "-";
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index cf247861f8..1e63a59576 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -446,6 +446,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type)
return (route_distance(ZEBRA_ROUTE_BGP));
case ZEBRA_LSP_NONE:
case ZEBRA_LSP_SHARP:
+ case ZEBRA_LSP_EVPN:
case ZEBRA_LSP_OSPF_SR:
case ZEBRA_LSP_ISIS_SR:
case ZEBRA_LSP_SRTE:
@@ -498,6 +499,7 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
case ZEBRA_LSP_LDP:
return ZEBRA_ROUTE_LDP;
case ZEBRA_LSP_BGP:
+ case ZEBRA_LSP_EVPN:
return ZEBRA_ROUTE_BGP;
case ZEBRA_LSP_OSPF_SR:
return ZEBRA_ROUTE_OSPF;
@@ -538,6 +540,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
return "SHARP";
case ZEBRA_LSP_SRTE:
return "SR-TE";
+ case ZEBRA_LSP_EVPN:
+ return "EVPN";
case ZEBRA_LSP_NONE:
return "Unknown";
}
diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c
index 0f3d56f214..45b9d440a6 100644
--- a/zebra/zebra_nb_state.c
+++ b/zebra/zebra_nb_state.c
@@ -25,6 +25,8 @@
#include "zebra/zebra_router.h"
#include "zebra/debug.h"
#include "printfrr.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/up-count
@@ -101,15 +103,18 @@ lib_interface_zebra_state_vni_id_get_elem(struct nb_cb_get_elem_args *args)
{
const struct interface *ifp = args->list_entry;
struct zebra_if *zebra_if;
- struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni *vni;
if (!IS_ZEBRA_IF_VXLAN(ifp))
return NULL;
zebra_if = ifp->info;
- vxlan_info = &zebra_if->l2info.vxl;
- return yang_data_new_uint32(args->xpath, vxlan_info->vni);
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zebra_if))
+ return NULL;
+
+ vni = zebra_vxlan_if_vni_find(zebra_if, 0);
+ return yang_data_new_uint32(args->xpath, vni->vni);
}
/*
@@ -139,15 +144,18 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args)
{
const struct interface *ifp = args->list_entry;
struct zebra_if *zebra_if;
- struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni *vni;
if (!IS_ZEBRA_IF_VXLAN(ifp))
return NULL;
zebra_if = ifp->info;
- vxlan_info = &zebra_if->l2info.vxl;
- return yang_data_new_ipv4(args->xpath, &vxlan_info->mcast_grp);
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zebra_if))
+ return NULL;
+
+ vni = zebra_vxlan_if_vni_find(zebra_if, 0);
+ return yang_data_new_ipv4(args->xpath, &vni->mcast_grp);
}
const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args)
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 0bca00ced3..d321ab4949 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -44,6 +44,7 @@
#include "zebra/interface.h"
#include "zebra/zapi_msg.h"
#include "zebra/rib.h"
+#include "zebra/zebra_vxlan.h"
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
@@ -1922,10 +1923,42 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
}
/*
- * When resolving a recursive nexthop, capture backup nexthop(s) also
- * so they can be conveyed through the dataplane to the FIB. We'll look
- * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
- * into the route's resolved nh 'resolved' and its nhe 'nhe'.
+ * Downstream VNI and Single VXlan device check.
+ *
+ * If it has nexthop VNI labels at this point it must be D-VNI allocated
+ * and all the nexthops have to be on an SVD.
+ *
+ * If SVD is not available, mark as inactive.
+ */
+static bool nexthop_set_evpn_dvni_svd(vrf_id_t re_vrf_id,
+ struct nexthop *nexthop)
+{
+ if (!is_vrf_l3vni_svd_backed(re_vrf_id)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ struct vrf *vrf = vrf_lookup_by_id(re_vrf_id);
+
+ zlog_debug(
+ "nexthop %pNHv D-VNI but route's vrf %s(%u) doesn't use SVD",
+ nexthop, VRF_LOGNAME(vrf), re_vrf_id);
+ }
+
+ return false;
+ }
+
+ nexthop->ifindex = get_l3vni_vxlan_ifindex(re_vrf_id);
+ nexthop->vrf_id = 0;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("nexthop %pNHv using SVD", nexthop);
+
+ return true;
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve
+ * the route. As such, do a table lookup to find and match
+ * if at all possible. Set the nexthop->ifindex and resolved_id
+ * as appropriate
*/
static int resolve_backup_nexthops(const struct nexthop *nexthop,
const struct nhg_hash_entry *nhe,
@@ -2195,6 +2228,12 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
* sure the nexthop's interface is known and is operational.
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
+ /* DVNI/SVD Checks for EVPN routes */
+ if (nexthop->nh_label &&
+ nexthop->nh_label_type == ZEBRA_LSP_EVPN &&
+ !nexthop_set_evpn_dvni_svd(vrf_id, nexthop))
+ return 0;
+
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (!ifp) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -2706,6 +2745,51 @@ done:
return valid;
}
+/* Checks if the first nexthop is EVPN. If not, early return.
+ *
+ * This is used to determine if there is a mismatch between l3VNI
+ * of the route's vrf and the nexthops in use's VNI labels.
+ *
+ * If there is a mismatch, we keep the labels as these MUST be DVNI nexthops.
+ *
+ * IF there is no mismatch, we remove the labels and handle the routes as
+ * we have traditionally with evpn.
+ */
+static bool nexthop_list_set_evpn_dvni(struct route_entry *re,
+ struct nexthop_group *nhg)
+{
+ struct nexthop *nexthop;
+ vni_t re_vrf_vni;
+ vni_t nh_vni;
+ bool use_dvni = false;
+
+ nexthop = nhg->nexthop;
+
+ if (!nexthop->nh_label || nexthop->nh_label_type != ZEBRA_LSP_EVPN)
+ return false;
+
+ re_vrf_vni = get_l3vni_vni(re->vrf_id);
+
+ for (; nexthop; nexthop = nexthop->next) {
+ if (!nexthop->nh_label ||
+ nexthop->nh_label_type != ZEBRA_LSP_EVPN)
+ continue;
+
+ nh_vni = label2vni(&nexthop->nh_label->label[0]);
+
+ if (nh_vni != re_vrf_vni)
+ use_dvni = true;
+ }
+
+ /* Using traditional way, no VNI encap - remove labels */
+ if (!use_dvni) {
+ for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next)
+ nexthop_del_labels(nexthop);
+ }
+
+ return use_dvni;
+}
+
/*
* Process a list of nexthops, given an nhe, determining
* whether each one is ACTIVE/installable at this time.
@@ -2721,12 +2805,16 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
uint32_t counter = 0;
struct nexthop *nexthop;
struct nexthop_group *nhg = &nhe->nhg;
+ bool vni_removed = false;
nexthop = nhg->nexthop;
/* Init recursive nh mtu */
re->nexthop_mtu = 0;
+ /* Handler for dvni evpn nexthops. Has to be done at nhg level */
+ vni_removed = !nexthop_list_set_evpn_dvni(re, nhg);
+
/* Process nexthops one-by-one */
for ( ; nexthop; nexthop = nexthop->next) {
@@ -2764,16 +2852,17 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
counter++;
/* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
- if (prev_active != new_active || prev_index != nexthop->ifindex
- || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
- && nexthop->type < NEXTHOP_TYPE_IPV6)
- && prev_src.ipv4.s_addr
- != nexthop->rmap_src.ipv4.s_addr)
- || ((nexthop->type >= NEXTHOP_TYPE_IPV6
- && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
- && !(IPV6_ADDR_SAME(&prev_src.ipv6,
- &nexthop->rmap_src.ipv6)))
- || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
+ if (prev_active != new_active ||
+ prev_index != nexthop->ifindex ||
+ ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
+ nexthop->type < NEXTHOP_TYPE_IPV6) &&
+ prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) ||
+ ((nexthop->type >= NEXTHOP_TYPE_IPV6 &&
+ nexthop->type < NEXTHOP_TYPE_BLACKHOLE) &&
+ !(IPV6_ADDR_SAME(&prev_src.ipv6,
+ &nexthop->rmap_src.ipv6))) ||
+ CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) ||
+ vni_removed)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
}
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 7b076b8a4a..457a4955b4 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -127,6 +127,8 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zebra_dplane_ns_enable(zns, true);
interface_list(zns);
route_read(zns);
+
+ vlan_read(zns);
kernel_read_pbr_rules(zns);
kernel_read_tc_qdisc(zns);
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index 4a18eb021e..937dc090a4 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -31,7 +31,6 @@
#include "ptm_lib.h"
#include "rib.h"
#include "stream.h"
-#include "lib/version.h"
#include "vrf.h"
#include "vty.h"
#include "lib_errors.h"
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index ba8073defe..415fc78142 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -99,42 +99,79 @@ static const struct {
uint8_t distance;
enum meta_queue_indexes meta_q_map;
} route_info[ZEBRA_ROUTE_MAX] = {
- [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */,
- META_QUEUE_NHG},
- [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, META_QUEUE_KERNEL},
- [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, META_QUEUE_KERNEL},
- [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, META_QUEUE_CONNECTED},
- [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, META_QUEUE_STATIC},
- [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */,
+ [ZEBRA_ROUTE_NHG] =
+ {ZEBRA_ROUTE_NHG,
+ ZEBRA_MAX_DISTANCE_DEFAULT /* Unneeded for nhg's */,
+ META_QUEUE_NHG},
+ [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM,
+ ZEBRA_KERNEL_DISTANCE_DEFAULT,
+ META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL,
+ ZEBRA_KERNEL_DISTANCE_DEFAULT,
+ META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT,
+ ZEBRA_CONNECT_DISTANCE_DEFAULT,
+ META_QUEUE_CONNECTED},
+ [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC,
+ ZEBRA_STATIC_DISTANCE_DEFAULT,
+ META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, ZEBRA_RIP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, ZEBRA_RIP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, ZEBRA_OSPF_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, ZEBRA_OSPF6_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, ZEBRA_ISIS_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP,
+ ZEBRA_EBGP_DISTANCE_DEFAULT /* IBGP is 200. */,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, META_QUEUE_STATIC},
- [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20,
+ [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, ZEBRA_EIGRP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, ZEBRA_NHRP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, ZEBRA_TABLE_DISTANCE_DEFAULT, META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, ZEBRA_LDP_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20,
+ [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115,
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, ZEBRA_BABEL_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, ZEBRA_SHARP_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, ZEBRA_PBR_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC,
+ ZEBRA_OPENFABRIC_DISTANCE_DEFAULT,
META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
@@ -4025,7 +4062,8 @@ static void _route_entry_dump_nh(const struct route_entry *re,
if (nexthop->nh_label && nexthop->nh_label->num_labels > 0) {
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, label_str,
- sizeof(label_str), 0 /*pretty*/);
+ sizeof(label_str), nexthop->nh_label_type,
+ 0 /*pretty*/);
strlcat(label_str, ", ", sizeof(label_str));
}
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 342a8d0f96..3bbb1f2325 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1413,8 +1413,14 @@ void show_nexthop_json_helper(json_object *json_nexthop,
label_index < nexthop->nh_label->num_labels; label_index++)
json_object_array_add(
json_labels,
- json_object_new_int(
- nexthop->nh_label->label[label_index]));
+ json_object_new_int((
+ (nexthop->nh_label_type ==
+ ZEBRA_LSP_EVPN)
+ ? label2vni(
+ &nexthop->nh_label->label
+ [label_index])
+ : nexthop->nh_label->label
+ [label_index])));
json_object_object_add(json_nexthop, "labels", json_labels);
}
@@ -1534,7 +1540,7 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re,
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ sizeof(buf), nexthop->nh_label_type, 1));
}
if (nexthop->nh_srv6) {
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 5f307f95e3..8f24404a44 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -1055,8 +1055,13 @@ route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
return RMAP_NOMATCH;
}
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1113,8 +1118,13 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
return RMAP_NOMATCH;
}
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1149,8 +1159,13 @@ route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
struct access_list *alist;
alist = access_list_lookup(afi, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1206,8 +1221,13 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix,
struct prefix_list *plist;
plist = prefix_list_lookup(afi, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index b013e59015..3b63821d37 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -420,7 +420,8 @@ static void show_nexthop_detail_helper(struct vty *vty,
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
- sizeof(buf), 1 /*pretty*/));
+ sizeof(buf), nexthop->nh_label_type,
+ 1 /*pretty*/));
}
if (nexthop->weight)
@@ -3018,20 +3019,37 @@ DEFPY(show_evpn_es_evi,
return CMD_SUCCESS;
}
-DEFPY(show_evpn_access_vlan,
- show_evpn_access_vlan_cmd,
- "show evpn access-vlan [(1-4094)$vid | detail$detail] [json$json]",
+DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd,
+ "show evpn access-vlan [IFNAME$if_name (1-4094)$vid | detail$detail] [json$json]",
SHOW_STR
"EVPN\n"
"Access VLANs\n"
+ "Interface Name\n"
"VLAN ID\n"
- "Detailed information\n"
- JSON_STR)
+ "Detailed information\n" JSON_STR)
{
bool uj = !!json;
- if (vid) {
- zebra_evpn_acc_vl_show_vid(vty, uj, vid);
+ if (if_name && vid) {
+ bool found = false;
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (if_name) {
+ ifp = if_lookup_by_name(if_name, vrf->vrf_id);
+ if (ifp) {
+ zebra_evpn_acc_vl_show_vid(vty, uj, vid,
+ ifp);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ vty_out(vty, "%% Can't find interface %s\n", if_name);
+ return CMD_WARNING;
+ }
} else {
if (detail)
zebra_evpn_acc_vl_show_detail(vty, uj);
@@ -3181,6 +3199,30 @@ DEFUN (show_evpn_nh_vni_ip,
return CMD_SUCCESS;
}
+DEFUN_HIDDEN (show_evpn_nh_svd_ip,
+ show_evpn_nh_svd_ip_cmd,
+ "show evpn next-hops svd ip WORD [json]",
+ SHOW_STR
+ "EVPN\n"
+ "Remote Vteps\n"
+ "Single Vxlan Device\n"
+ "Ip address\n"
+ "Host address (ipv4 or ipv6)\n"
+ JSON_STR)
+{
+ struct ipaddr ip;
+ bool uj = use_json(argc, argv);
+
+ if (str2ipaddr(argv[5]->arg, &ip) != 0) {
+ if (!uj)
+ vty_out(vty, "%% Malformed Neighbor address\n");
+ return CMD_WARNING;
+ }
+ zebra_vxlan_print_specific_nh_l3vni(vty, 0, &ip, uj);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_evpn_nh_vni,
show_evpn_nh_vni_cmd,
"show evpn next-hops vni " CMD_VNI_RANGE "[json]",
@@ -3200,6 +3242,22 @@ DEFUN (show_evpn_nh_vni,
return CMD_SUCCESS;
}
+DEFUN_HIDDEN (show_evpn_nh_svd,
+ show_evpn_nh_svd_cmd,
+ "show evpn next-hops svd [json]",
+ SHOW_STR
+ "EVPN\n"
+ "Remote VTEPs\n"
+ "Single Vxlan Device\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+
+ zebra_vxlan_print_nh_svd(vty, uj);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_evpn_nh_vni_all,
show_evpn_nh_vni_all_cmd,
"show evpn next-hops vni all [json]",
@@ -4557,7 +4615,9 @@ void zebra_vty_init(void)
install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
+ install_element(VIEW_NODE, &show_evpn_nh_svd_ip_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
+ install_element(VIEW_NODE, &show_evpn_nh_svd_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 0bbc811324..4baa3d64af 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -46,13 +46,14 @@
#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"
@@ -72,6 +73,9 @@ DEFINE_HOOK(zebra_rmac_update,
/* 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);
@@ -92,6 +96,11 @@ static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
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 *);
@@ -110,8 +119,6 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
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);
@@ -121,10 +128,6 @@ static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
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)
@@ -375,11 +378,16 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
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(
@@ -387,13 +395,19 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
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);
+ }
}
}
@@ -597,33 +611,36 @@ static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
}
}
-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);
@@ -631,11 +648,26 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
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)
{
@@ -728,6 +760,9 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx)
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",
@@ -889,7 +924,6 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
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. */
@@ -899,8 +933,7 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
/* 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;
@@ -915,9 +948,11 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
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);
@@ -925,6 +960,136 @@ static int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
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)))
@@ -938,9 +1103,6 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
/* 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;
@@ -952,126 +1114,23 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
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;
}
@@ -1225,7 +1284,7 @@ static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
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;
@@ -1242,17 +1301,17 @@ static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
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;
@@ -1267,7 +1326,7 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
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;
@@ -1292,16 +1351,16 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
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
@@ -1424,21 +1483,41 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni,
}
/*
- * 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.
@@ -1455,18 +1534,24 @@ static void *zl3vni_nh_alloc(void *p)
}
/*
- * 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);
@@ -1478,6 +1563,16 @@ static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
}
/*
+ * 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.
*/
static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
@@ -1499,14 +1594,38 @@ static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
}
/*
- * 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)
@@ -1517,31 +1636,63 @@ static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
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,
@@ -1579,7 +1730,7 @@ static int zl3vni_remote_nh_add(struct zebra_l3vni *zl3vni,
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)
@@ -1595,6 +1746,91 @@ static void zl3vni_remote_nh_del(struct zebra_l3vni *zl3vni,
}
}
+/* 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)
+{
+ struct zebra_neigh *nh = NULL;
+
+ /* SVD backed VNI check */
+ if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
+ 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;
+ }
+
+ } 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.
*/
@@ -1756,7 +1992,8 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
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)
@@ -1767,7 +2004,8 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
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 */
@@ -1776,12 +2014,12 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
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;
}
@@ -1804,7 +2042,7 @@ struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni)
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;
@@ -1816,9 +2054,11 @@ struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
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)
@@ -1853,6 +2093,8 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
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 =
@@ -1860,33 +2102,46 @@ static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
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;
}
/*
@@ -1898,7 +2153,6 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
{
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;
@@ -1913,8 +2167,7 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
/* 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;
@@ -2061,7 +2314,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni)
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;
@@ -2070,7 +2323,7 @@ static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
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;
@@ -2142,6 +2395,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
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;
@@ -2161,7 +2415,8 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == vni) {
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (vnip) {
found = true;
break;
}
@@ -2183,7 +2438,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
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;
@@ -2282,6 +2537,9 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
*/
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
@@ -2325,6 +2583,9 @@ void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
/* 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);
@@ -2454,22 +2715,29 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
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;
}
@@ -2480,26 +2748,14 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
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;
@@ -2515,12 +2771,45 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
} 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;
@@ -3953,20 +4242,17 @@ stream_failure:
/*
* 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())
@@ -3977,6 +4263,10 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
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)
@@ -4004,18 +4294,14 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
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())
@@ -4067,7 +4353,8 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
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;
@@ -4083,7 +4370,8 @@ int zebra_vxlan_dp_network_mac_add(struct interface *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)
@@ -4091,8 +4379,8 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
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
@@ -4113,19 +4401,16 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
*/
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())
@@ -4804,507 +5089,6 @@ void zebra_vxlan_macvlan_up(struct interface *ifp)
}
}
-/*
- * Handle VxLAN interface down
- */
-int zebra_vxlan_if_down(struct interface *ifp)
-{
- 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;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- 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);
-
- 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);
-
- /* 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);
- return -1;
- }
-
- assert(zevpn->vxlan_if == ifp);
-
- /* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
- if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zevpn);
-
- /* Delete this VNI from BGP. */
- zebra_evpn_send_del_to_client(zevpn);
-
- /* 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);
-
- /* Free up all remote VTEPs, if any. */
- zebra_evpn_vtep_del_all(zevpn, 1);
- }
- return 0;
-}
-
-/*
- * 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)
@@ -5557,8 +5341,8 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
} 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);
@@ -5592,8 +5376,11 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
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;
@@ -5623,8 +5410,8 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
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",
@@ -5661,10 +5448,12 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
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;
@@ -5723,9 +5512,9 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
} 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);
@@ -5755,9 +5544,11 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
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;
@@ -5934,6 +5725,9 @@ void zebra_vxlan_init(void)
{
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();
}
@@ -5957,6 +5751,42 @@ ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
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,
@@ -6140,8 +5970,8 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(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;
@@ -6156,8 +5986,7 @@ static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
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;
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 16c5bc0a1a..b33c215c73 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -36,6 +36,7 @@
#include "zebra/zebra_vrf.h"
#include "zebra/zserv.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/interface.h"
#ifdef __cplusplus
extern "C" {
@@ -62,6 +63,10 @@ is_vxlan_flooding_head_end(void)
#define ZEBRA_VXLIF_MCAST_GRP_CHANGE (1 << 3)
#define ZEBRA_VXLIF_MASTER_MAC_CHANGE (1 << 4)
+#define ZEBRA_VXLIF_VNI_UPDATE(__flags) \
+ ((__flags) & (ZEBRA_VXLIF_VLAN_CHANGE | ZEBRA_VXLIF_MCAST_GRP_CHANGE))
+#define ZEBRA_VXLIF_UPDATE(__flags) \
+ ((__flags) & (ZEBRA_VXLIF_LOCAL_IP_CHANGE | ZEBRA_VXLIF_MASTER_CHANGE))
#define VNI_STR_LEN 32
@@ -84,6 +89,9 @@ extern void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS);
extern int is_l3vni_for_prefix_routes_only(vni_t vni);
extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
+extern ifindex_t get_l3vni_vxlan_ifindex(vrf_id_t vrf_id);
+extern vni_t get_l3vni_vni(vrf_id_t vrf_id);
+extern bool is_vrf_l3vni_svd_backed(vrf_id_t vrf_id);
extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
extern int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf);
extern int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf);
@@ -153,6 +161,7 @@ extern void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t vni,
extern void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni,
bool use_json);
+extern void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json);
extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
@@ -177,12 +186,13 @@ extern int zebra_vxlan_local_mac_add_update(struct interface *ifp,
extern int zebra_vxlan_local_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
-extern int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+extern int zebra_vxlan_check_readd_vtep(struct interface *ifp, vni_t vni,
struct in_addr vtep_ip);
extern int zebra_vxlan_if_up(struct interface *ifp);
extern int zebra_vxlan_if_down(struct interface *ifp);
extern int zebra_vxlan_if_add(struct interface *ifp);
-extern int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags);
+extern int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx);
extern int zebra_vxlan_if_del(struct interface *ifp);
extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
char *err, int err_str_sz,
@@ -218,12 +228,12 @@ extern int vni_list_cmp(void *p1, void *p2);
extern 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);
extern 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);
extern void zebra_vxlan_set_accept_bgp_seq(bool set);
extern bool zebra_vxlan_get_accept_bgp_seq(void);
diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c
new file mode 100644
index 0000000000..08e07b60a2
--- /dev/null
+++ b/zebra/zebra_vxlan_if.c
@@ -0,0 +1,1162 @@
+/*
+ * Zebra EVPN for VxLAN interface handling
+ *
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Vivek Venkatraman, Stephen Worley, Sharath Ramamurthy
+ *
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+#include "vlan.h"
+#include "vxlan.h"
+#ifdef GNU_LINUX
+#include <linux/neighbour.h>
+#endif
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.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"
+
+static unsigned int zebra_vxlan_vni_hash_keymake(const void *p)
+{
+ const struct zebra_vxlan_vni *vni;
+
+ vni = (const struct zebra_vxlan_vni *)p;
+ return jhash_1word(vni->vni, 0);
+}
+
+static bool zebra_vxlan_vni_hash_cmp(const void *p1, const void *p2)
+{
+ const struct zebra_vxlan_vni *vni1;
+ const struct zebra_vxlan_vni *vni2;
+
+ vni1 = (const struct zebra_vxlan_vni *)p1;
+ vni2 = (const struct zebra_vxlan_vni *)p2;
+
+ return (vni1->vni == vni2->vni);
+}
+
+static int zebra_vxlan_if_vni_walk_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ int ret;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_ctx *ctx;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ ctx = (struct zebra_vxlan_if_ctx *)ctxt;
+
+ ret = ctx->func(ctx->zif, vni, ctx->arg);
+ return ret;
+}
+
+static void zebra_vxlan_if_vni_iterate_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_ctx *ctx;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ ctx = (struct zebra_vxlan_if_ctx *)ctxt;
+
+ ctx->func(ctx->zif, vni, ctx->arg);
+}
+
+static int zebra_vxlan_if_del_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->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;
+ zl3vni->vid = 0;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, false /* unset */);
+ } 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, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zebra_evpn_vtep_del_all(zevpn, 1);
+
+ /* 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;
+}
+
+static int zebra_vxlan_if_update_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip,
+ struct zebra_vxlan_if_update_ctx *ctx)
+{
+ vni_t vni;
+ uint16_t chgflags;
+ vlanid_t access_vlan;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *vlan_if;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vxl = &zif->l2info.vxl;
+ vni = vnip->vni;
+ chgflags = ctx->chgflags;
+
+ 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, vnip->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;
+
+ zl3vni->vid = (zl3vni->vid != vnip->access_vlan)
+ ? vnip->access_vlan
+ : zl3vni->vid;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, true /* set */);
+
+ /* 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, vnip->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)
+ */
+ access_vlan = vnip->access_vlan;
+ vnip->access_vlan = ctx->old_vni.access_vlan;
+ zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_rem_mac_uninstall_all(zevpn);
+ vnip->access_vlan = access_vlan;
+ }
+
+ 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 */);
+ zevpn->vid = (zevpn->vid != vnip->access_vlan)
+ ? vnip->access_vlan
+ : zevpn->vid;
+ 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->svi_if = vlan_if;
+
+ /* 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 neigh_walk_ctx n_wctx;
+
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+
+ zebra_evpn_rem_mac_install_all(zevpn);
+
+ 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;
+}
+
+static int zebra_vxlan_if_add_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vxl = &zif->l2info.vxl;
+ vni = vnip->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, vnip->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);
+
+ zl3vni->vid = vnip->access_vlan;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, true /* set */);
+
+ 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 != 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_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, vnip->access_vlan,
+ &vxl->vtep_ip, &vnip->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;
+}
+
+static void zebra_vxlan_if_vni_entry_del(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni)
+{
+ if (vni) {
+ zebra_evpn_vl_vxl_deref(vni->access_vlan, vni->vni, zif);
+ zebra_vxlan_if_del_vni(zif->ifp, vni);
+ }
+}
+
+static int zebra_vxlan_if_vni_entry_add(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni)
+{
+ zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif);
+ return zebra_vxlan_if_add_vni(zif->ifp, vni);
+}
+
+static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ struct zebra_vxlan_vni vni_tmp;
+ struct zebra_vxlan_if_update_ctx *ctx;
+ struct zebra_vxlan_vni *old_vni = NULL;
+
+ ctx = (struct zebra_vxlan_if_update_ctx *)ctxt;
+ memcpy(&vni_tmp, vni, sizeof(*vni));
+
+ if ((hashcount(ctx->old_vni_table) == 0) ||
+ !(old_vni = hash_release(ctx->old_vni_table, &vni_tmp))) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("vxlan %s adding vni(%d, %d)",
+ zif->ifp->name, vni->vni, vni->access_vlan);
+
+ zebra_vxlan_if_vni_entry_add(zif, &vni_tmp);
+ return 0;
+ }
+
+ ctx->old_vni = *old_vni;
+ ctx->chgflags = ZEBRA_VXLIF_VLAN_CHANGE;
+
+ /* copy mcast group from old_vni as thats not being changed here */
+ vni->mcast_grp = old_vni->mcast_grp;
+
+ if (old_vni->access_vlan != vni->access_vlan) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "vxlan %s updating vni(%d, %d) -> vni(%d, %d)",
+ zif->ifp->name, old_vni->vni,
+ old_vni->access_vlan, vni->vni,
+ vni->access_vlan);
+
+ zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni,
+ zif);
+ zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif);
+ zebra_vxlan_if_update_vni(zif->ifp, vni, ctx);
+ zebra_vxlan_vni_free(old_vni);
+ }
+
+ return 0;
+}
+
+static int zebra_vxlan_if_vni_entry_update_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ struct zebra_vxlan_if_update_ctx *ctx;
+
+ ctx = (struct zebra_vxlan_if_update_ctx *)ctxt;
+ return zebra_vxlan_if_update_vni(zif->ifp, vni, ctx);
+}
+
+static int zebra_vxlan_if_vni_entry_del_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ zebra_vxlan_if_vni_entry_del(zif, vni);
+ return 0;
+}
+
+static int zebra_vxlan_if_vni_entry_down_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ return zebra_vxlan_if_vni_down(zif->ifp, vni);
+}
+
+static int zebra_vxlan_if_vni_entry_up_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ return zebra_vxlan_if_vni_up(zif->ifp, vni);
+}
+
+static void zebra_vxlan_if_vni_clean(struct hash_bucket *bucket, void *arg)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vni;
+
+ zif = (struct zebra_if *)arg;
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ zebra_vxlan_if_vni_entry_del(zif, vni);
+}
+
+void zebra_vxlan_vni_free(void *arg)
+{
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)arg;
+
+ XFREE(MTYPE_TMP, vni);
+}
+
+void *zebra_vxlan_vni_alloc(void *p)
+{
+ struct zebra_vxlan_vni *vni;
+ const struct zebra_vxlan_vni *vnip;
+
+ vnip = (const struct zebra_vxlan_vni *)p;
+ vni = XCALLOC(MTYPE_TMP, sizeof(*vni));
+ vni->vni = vnip->vni;
+ vni->access_vlan = vnip->access_vlan;
+ vni->mcast_grp = vnip->mcast_grp;
+
+ return (void *)vni;
+}
+
+struct hash *zebra_vxlan_vni_table_create(void)
+{
+ return hash_create(zebra_vxlan_vni_hash_keymake,
+ zebra_vxlan_vni_hash_cmp, "Zebra Vxlan VNI Table");
+}
+
+void zebra_vxlan_vni_table_destroy(struct hash *vni_table)
+{
+ if (vni_table) {
+ hash_clean(vni_table, zebra_vxlan_vni_free);
+ hash_free(vni_table);
+ }
+}
+
+int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (vni_info->vni_table) {
+ zebra_vxlan_if_vni_iterate(
+ zif, zebra_vxlan_if_vni_entry_del_callback, NULL);
+ zebra_vxlan_vni_table_destroy(vni_info->vni_table);
+ vni_info->vni_table = NULL;
+ }
+ return 0;
+}
+
+int zebra_vxlan_if_vni_table_create(struct zebra_if *zif)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ vni_info->vni_table = zebra_vxlan_vni_table_create();
+ if (!vni_info->vni_table)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct zebra_vxlan_vni *zebra_vxlan_if_vni_find(const struct zebra_if *zif,
+ vni_t vni)
+{
+ struct zebra_vxlan_vni *vnip = NULL;
+ const struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni vni_tmp;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vnip = (struct zebra_vxlan_vni *)&vni_info->vni;
+ assert(vnip);
+ if (vni && (vnip->vni != vni))
+ vnip = NULL;
+
+ return vnip;
+ }
+
+ /* For SVD, the VNI value is a required parameter. */
+ assert(vni);
+
+ memset(&vni_tmp, 0, sizeof(vni_tmp));
+ vni_tmp.vni = vni;
+ vnip = (struct zebra_vxlan_vni *)hash_lookup(vni_info->vni_table,
+ (void *)&vni_tmp);
+
+ /* TODO: For debugging. Remove later */
+ if (vnip)
+ assert(vnip->vni == vni);
+
+ return vnip;
+}
+
+static int zif_vlanid_vni_walker(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vnip, void *arg)
+{
+ struct zebra_vxlan_if_vlan_ctx *ctx;
+
+ ctx = (struct zebra_vxlan_if_vlan_ctx *)arg;
+
+ if (vnip->access_vlan == ctx->vid) {
+ ctx->vni = vnip;
+ return HASHWALK_ABORT;
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+struct zebra_vxlan_vni *zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif,
+ vlanid_t vid)
+{
+ struct zebra_vxlan_if_vlan_ctx ctx = {};
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return NULL;
+
+ ctx.vid = vid;
+
+ zebra_vxlan_if_vni_walk(zif, zif_vlanid_vni_walker, &ctx);
+
+ return ctx.vni;
+}
+
+void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *, void *),
+ void *arg)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni *vni = NULL;
+ struct zebra_vxlan_if_ctx ctx;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ func(zif, vni, arg);
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_iterate(vni_info->vni_table, zebra_vxlan_if_vni_iterate_callback,
+ &ctx);
+}
+
+void zebra_vxlan_if_vni_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *, void *),
+ void *arg)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni *vni = NULL;
+ struct zebra_vxlan_if_ctx ctx;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ func(zif, vni, arg);
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_walk(vni_info->vni_table, zebra_vxlan_if_vni_walk_callback, &ctx);
+}
+
+vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif,
+ struct interface *br_if)
+{
+ struct zebra_vxlan_vni *vni = NULL;
+
+ /* Expected to be called only for vlan-unware bridges. In this case,
+ * we only support a per-VNI VXLAN interface model.
+ */
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ assert(vni);
+
+ return vni->vni;
+}
+
+int zebra_vxlan_if_vni_table_add_update(struct interface *ifp,
+ struct hash *vni_table)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni_table = vni_info->vni_table;
+ vni_info->vni_table = vni_table;
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_add_update_vni, &ctx);
+
+ /* release kernel deleted vnis */
+ if (ctx.old_vni_table) {
+ if (hashcount(ctx.old_vni_table)) {
+ /* UGLY HACK: Put back the old table so that delete of
+ * MACs goes through and then flip back.
+ */
+ vni_info->vni_table = ctx.old_vni_table;
+ hash_iterate(ctx.old_vni_table,
+ zebra_vxlan_if_vni_clean, zif);
+ vni_info->vni_table = vni_table;
+ }
+ zebra_vxlan_vni_table_destroy(ctx.old_vni_table);
+ ctx.old_vni_table = NULL;
+ }
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_mcast_group_add_update(struct interface *ifp,
+ vni_t vni_id,
+ struct in_addr *mcast_group)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, vni_id);
+ if (!vni)
+ return 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni.mcast_grp = vni->mcast_grp;
+ ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+
+ vni->mcast_grp = *mcast_group;
+
+ return zebra_vxlan_if_update_vni(ifp, vni, &ctx);
+}
+
+int zebra_vxlan_if_vni_mcast_group_del(struct interface *ifp, vni_t vni_id,
+ struct in_addr *mcast_group)
+{
+ struct zebra_if *zif = NULL;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, vni_id);
+ if (!vni)
+ return 0;
+
+ if (memcmp(mcast_group, &vni->mcast_grp, sizeof(*mcast_group)))
+ return 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni.mcast_grp = vni->mcast_grp;
+ ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+
+ memset(&vni->mcast_grp, 0, sizeof(vni->mcast_grp));
+
+ return zebra_vxlan_if_update_vni(ifp, vni, &ctx);
+}
+
+int zebra_vxlan_if_vni_down(struct interface *ifp, struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_l3vni *zl3vni;
+ struct zebra_evpn *zevpn;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->vni;
+
+ 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);
+
+ 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);
+
+ /* 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);
+ return -1;
+ }
+
+ assert(zevpn->vxlan_if == ifp);
+
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zevpn);
+
+ zebra_evpn_vl_vxl_deref(vnip->access_vlan, vnip->vni, zif);
+
+ /* Delete this VNI from BGP. */
+ zebra_evpn_send_del_to_client(zevpn);
+
+ /* 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);
+
+ /* Free up all remote VTEPs, if any. */
+ zebra_evpn_vtep_del_all(zevpn, 1);
+ }
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface down
+ */
+int zebra_vxlan_if_down(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_vni_down(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_down_callback,
+ NULL);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_up(struct interface *ifp, struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->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);
+ zebra_evpn_vl_vxl_ref(vnip->access_vlan, vnip->vni, zif);
+ vlan_if = zvni_map_to_svi(vnip->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 up - update BGP if required.
+ */
+int zebra_vxlan_if_up(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_vni_up(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_up_callback,
+ NULL);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_del(struct interface *ifp, vni_t vni)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vnip;
+ struct zebra_vxlan_vni vni_tmp;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* This should be called in SVD context only */
+ assert(IS_ZEBRA_VXLAN_IF_SVD(zif));
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ memset(&vni_tmp, 0, sizeof(vni_tmp));
+ vni_tmp.vni = vni;
+
+ vnip = hash_release(vni_info->vni_table, &vni_tmp);
+ if (vnip) {
+ zebra_vxlan_if_vni_entry_del(zif, vnip);
+ zebra_vxlan_vni_free(vnip);
+ }
+ 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)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ zebra_evpn_vl_vxl_deref(vni_info->vni.access_vlan,
+ vni_info->vni.vni, zif);
+ return zebra_vxlan_if_del_vni(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_table_destroy(zif);
+
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
+ */
+int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_update_vni(ifp, &vni_info->vni, ctx);
+ }
+
+ zebra_vxlan_if_vni_iterate(
+ zif, zebra_vxlan_if_vni_entry_update_callback, ctx);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_add(struct interface *ifp, struct zebra_vxlan_vni *vni)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* This should be called in SVD context only */
+ assert(IS_ZEBRA_VXLAN_IF_SVD(zif));
+
+ /* First insert into the table */
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ hash_get(vni_info->vni_table, (void *)vni, zebra_vxlan_vni_alloc);
+
+ return zebra_vxlan_if_vni_entry_add(zif, vni);
+}
+
+/*
+ * Handle VxLAN interface add.
+ */
+int zebra_vxlan_if_add(struct interface *ifp)
+{
+ int ret;
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ zebra_evpn_vl_vxl_ref(vni_info->vni.access_vlan,
+ vni_info->vni.vni, zif);
+ return zebra_vxlan_if_add_vni(ifp, &vni_info->vni);
+ }
+
+ ret = zebra_vxlan_if_vni_table_create(zif);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/zebra/zebra_vxlan_if.h b/zebra/zebra_vxlan_if.h
new file mode 100644
index 0000000000..8a03acbf1e
--- /dev/null
+++ b/zebra/zebra_vxlan_if.h
@@ -0,0 +1,96 @@
+/*
+ * Zebra VxLAN (EVPN) interface data structures and definitions
+ * These are public definitions referenced by other files.
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_VXLAN_IF_H
+#define _ZEBRA_VXLAN_IF_H
+
+#include <zebra.h>
+#include <zebra/zebra_router.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "lib/json.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_dplane.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void *zebra_vxlan_vni_alloc(void *p);
+extern void zebra_vxlan_vni_free(void *arg);
+extern struct hash *zebra_vxlan_vni_table_create(void);
+extern void zebra_vxlan_vni_table_destroy(struct hash *vni_table);
+extern int zebra_vxlan_if_vni_table_create(struct zebra_if *zif);
+extern int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif);
+extern struct zebra_vxlan_vni *
+zebra_vxlan_if_vni_find(const struct zebra_if *zif, vni_t vni);
+extern struct zebra_vxlan_vni *
+zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif, vlanid_t vni);
+extern void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *,
+ void *),
+ void *arg);
+extern void zebra_vxlan_if_vni_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *,
+ void *),
+ void *arg);
+extern vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif,
+ struct interface *br_if);
+extern int
+zebra_vxlan_if_vni_mcast_group_add_update(struct interface *ifp, vni_t vni_id,
+ struct in_addr *mcast_group);
+extern int zebra_vxlan_if_vni_mcast_group_del(struct interface *ifp,
+ vni_t vni_id,
+ struct in_addr *mcast_group);
+extern int zebra_vxlan_if_vni_down(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_down(struct interface *ifp);
+extern int zebra_vxlan_if_vni_up(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_up(struct interface *ifp);
+extern int zebra_vxlan_if_vni_del(struct interface *ifp, vni_t vni);
+extern int zebra_vxlan_if_del(struct interface *ifp);
+extern int zebra_vxlan_if_vni_table_add_update(struct interface *ifp,
+ struct hash *vni_table);
+extern int zebra_vxlan_if_vni_update(struct interface *ifp,
+ struct zebra_vxlan_vni *vni,
+ uint16_t chgflags);
+extern int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx);
+extern int zebra_vxlan_if_vni_add(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_add(struct interface *ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_VXLAN_IF_H */
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index fb17dac23e..7b8cdef409 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -29,6 +29,7 @@
#include "if.h"
#include "linklist.h"
#include "zebra_vxlan.h"
+#include "zebra_vxlan_if.h"
#include "zebra_evpn.h"
#include "zebra_evpn_mac.h"
@@ -50,6 +51,10 @@ struct zebra_l3vni {
uint32_t filter;
#define PREFIX_ROUTES_ONLY (1 << 0) /* l3-vni used for prefix routes only */
+ /* Corresponding Bridge information */
+ vlanid_t vid;
+ struct interface *bridge_if;
+
/* Local IP */
struct in_addr local_vtep_ip;
@@ -71,6 +76,10 @@ struct zebra_l3vni {
struct hash *nh_table;
};
+#define IS_ZL3VNI_SVD_BACKED(zl3vni) \
+ (zl3vni->vxlan_if && zl3vni->vxlan_if->info && \
+ IS_ZEBRA_VXLAN_IF_SVD((struct zebra_if *)zl3vni->vxlan_if->info))
+
/* get the vx-intf name for l3vni */
static inline const char *zl3vni_vxlan_if_name(struct zebra_l3vni *zl3vni)
{
@@ -260,5 +269,12 @@ extern void zebra_vxlan_sync_mac_dp_install(struct zebra_mac *mac,
bool force_clear_static,
const char *caller);
extern bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf);
+extern void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp);
+extern void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp);
+extern void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni);
+extern void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni);
+extern int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn);
#endif /* _ZEBRA_VXLAN_PRIVATE_H */