+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Zebra EVPN for VxLAN code
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
*/
#include <zebra.h>
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
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);
void *_in_param,
void **_p_zevpn)
{
+ int found = 0;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if;
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_vxlan_vni *vni;
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;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
+ vid = in_param->vid;
+ bridge_vlan_aware = in_param->bridge_vlan_aware;
- vni = zebra_vxlan_if_access_vlan_find(
- zif, in_param->bridge_vlan_aware, in_param->vid);
-
- if (!in_param->bridge_vlan_aware || vni) {
- zevpn = zebra_evpn_lookup(vni->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;
}
/*
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_vxlan_vni *vni;
+ 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;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- vni = zebra_vxlan_if_access_vlan_find(
- zif, in_param->bridge_vlan_aware, in_param->vid);
- if (!in_param->bridge_vlan_aware || vni) {
+ 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(vni->vni);
+ zevpn = zebra_evpn_lookup(vni_id);
if (p_zevpn)
*p_zevpn = zevpn;
return NS_WALK_STOP;
return tmp_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;
zebra_evpn_rem_mac_install(wctx->zevpn, mac, false);
}
+/*
+ * 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.
*/
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 */