The EVPN FDB was matching only on the MAC address itself, that
would cause issues when there would be 2 EVPN fabrics but same
MAC address for a workload. Only the "last" would be learned.
Add VNI into the structure to ensure that the FDB is unique
per MAC and also per VNI.

Fixes: 3826e4071afb ("controller: Create physical flows based on the advertised 
EVPN FDBs.")
Reported-at: https://issues.redhat.com/browse/FDP-1730
Signed-off-by: Ales Musil <[email protected]>
---
 controller/evpn-fdb.c | 40 +++++++++++++++++++++++++++-------------
 controller/evpn-fdb.h |  1 +
 tests/system-ovn.at   |  4 ++--
 3 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/controller/evpn-fdb.c b/controller/evpn-fdb.c
index acef8f0a4..6767a70a5 100644
--- a/controller/evpn-fdb.c
+++ b/controller/evpn-fdb.c
@@ -28,9 +28,11 @@ VLOG_DEFINE_THIS_MODULE(evpn_fdb);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
 
-static struct evpn_fdb *evpn_fdb_add(struct hmap *evpn_fdbs, struct eth_addr);
+static struct evpn_fdb *evpn_fdb_add(struct hmap *evpn_fdbs, struct eth_addr,
+                                     uint32_t vni);
 static struct evpn_fdb *evpn_fdb_find(const struct hmap *evpn_fdbs,
-                                      struct eth_addr);
+                                      struct eth_addr, uint32_t vni);
+static uint32_t evpn_fdb_hash(const struct eth_addr *mac, uint32_t vni);
 
 void
 evpn_fdb_run(const struct evpn_fdb_ctx_in *f_ctx_in,
@@ -54,9 +56,10 @@ evpn_fdb_run(const struct evpn_fdb_ctx_in *f_ctx_in,
             continue;
         }
 
-        fdb = evpn_fdb_find(f_ctx_out->fdbs, static_fdb->mac);
+        fdb = evpn_fdb_find(f_ctx_out->fdbs, static_fdb->mac, static_fdb->vni);
         if (!fdb) {
-            fdb = evpn_fdb_add(f_ctx_out->fdbs, static_fdb->mac);
+            fdb = evpn_fdb_add(f_ctx_out->fdbs, static_fdb->mac,
+                               static_fdb->vni);
         }
 
         bool updated = false;
@@ -109,9 +112,10 @@ evpn_fdb_list(struct unixctl_conn *conn, int argc 
OVS_UNUSED,
     const struct evpn_fdb *fdb;
     HMAP_FOR_EACH (fdb, hmap_node, fdbs) {
         ds_put_format(&ds, "UUID: "UUID_FMT", MAC: "ETH_ADDR_FMT", "
-                      "binding_key: %#"PRIx32", dp_key: %"PRIu32"\n",
+                      "vni: %"PRIu32", binding_key: %#"PRIx32", "
+                      "dp_key: %"PRIu32"\n",
                       UUID_ARGS(&fdb->flow_uuid), ETH_ADDR_ARGS(fdb->mac),
-                      fdb->binding_key, fdb->dp_key);
+                      fdb->vni, fdb->binding_key, fdb->dp_key);
     }
 
     unixctl_command_reply(conn, ds_cstr_ro(&ds));
@@ -119,33 +123,43 @@ evpn_fdb_list(struct unixctl_conn *conn, int argc 
OVS_UNUSED,
 }
 
 static struct evpn_fdb *
-evpn_fdb_add(struct hmap *evpn_fdbs, struct eth_addr mac)
+evpn_fdb_add(struct hmap *evpn_fdbs, struct eth_addr mac, uint32_t vni)
 {
     struct evpn_fdb *fdb = xmalloc(sizeof *fdb);
     *fdb = (struct evpn_fdb) {
         .flow_uuid = uuid_random(),
         .mac = mac,
-        .binding_key = 0,
-        .dp_key = 0,
+        .vni = vni,
     };
 
-    uint32_t hash = hash_bytes(&mac, sizeof mac, 0);
+    uint32_t hash = evpn_fdb_hash(&mac, vni);
     hmap_insert(evpn_fdbs, &fdb->hmap_node, hash);
 
     return fdb;
 }
 
 static struct evpn_fdb *
-evpn_fdb_find(const struct hmap *evpn_fdbs, struct eth_addr mac)
+evpn_fdb_find(const struct hmap *evpn_fdbs, struct eth_addr mac, uint32_t vni)
 {
-    uint32_t hash = hash_bytes(&mac, sizeof mac, 0);
+    uint32_t hash = evpn_fdb_hash(&mac, vni);
 
     struct evpn_fdb *fdb;
     HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, evpn_fdbs) {
-        if (eth_addr_equals(fdb->mac, mac)) {
+        if (eth_addr_equals(fdb->mac, mac) &&
+            fdb->vni == vni) {
             return fdb;
         }
     }
 
     return NULL;
 }
+
+static uint32_t
+evpn_fdb_hash(const struct eth_addr *mac, uint32_t vni)
+{
+    uint32_t hash = 0;
+    hash = hash_bytes(mac, sizeof *mac, hash);
+    hash = hash_add(hash, vni);
+
+    return hash_finish(hash, 10);
+}
diff --git a/controller/evpn-fdb.h b/controller/evpn-fdb.h
index de58df813..35c5db040 100644
--- a/controller/evpn-fdb.h
+++ b/controller/evpn-fdb.h
@@ -46,6 +46,7 @@ struct evpn_fdb {
     struct uuid flow_uuid;
     /* IP address of the remote VTEP. */
     struct eth_addr mac;
+    uint32_t vni;
     /* Local tunnel key to identify the binding. */
     uint32_t binding_key;
     uint32_t dp_key;
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 64ec460ba..02489ecb2 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -18551,8 +18551,8 @@ check bridge fdb add f0:00:0f:16:10:50 dev vxlan-$vni 
dst 169.0.0.10 static exte
 check bridge fdb add f0:00:0f:16:10:60 dev vxlan-$vni dst 169.0.0.20 static 
extern_learn
 
 OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-fdb-list | cut -d',' -f2- | 
sort], [0], [dnl
- MAC: f0:00:0f:16:10:50, binding_key: 0x80000001, dp_key: $dp_key
- MAC: f0:00:0f:16:10:60, binding_key: 0x80000002, dp_key: $dp_key
+ MAC: f0:00:0f:16:10:50, vni: $vni, binding_key: 0x80000001, dp_key: $dp_key
+ MAC: f0:00:0f:16:10:60, vni: $vni, binding_key: 0x80000002, dp_key: $dp_key
 ])
 
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_GET_REMOTE_FDB | 
grep priority | \
-- 
2.51.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to