]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_evpn.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_evpn.c
index 6f2765284b22f294c9e705afc9f0a5d0c1262b26..ce5e6399285000336910a623fa9476bc5f6071ee 100644 (file)
@@ -1,23 +1,7 @@
+// 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>
 
@@ -44,6 +28,7 @@
 #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"
@@ -117,6 +102,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);
@@ -663,6 +651,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;
@@ -670,43 +659,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_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;
 }
 
 /*
@@ -747,43 +752,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_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;
@@ -905,10 +927,25 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
        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;
@@ -919,6 +956,44 @@ void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *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.
  */
@@ -946,6 +1021,10 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
 
        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 */