In addition to MAC bindings that have aging enabled
keep track of FDB with aging enabled. This allows
the data to be used to update timestamp.

This is a preparation for the FDB refresh mechanism.

Signed-off-by: Ales Musil <[email protected]>
---
 controller/mac_cache.c      | 138 +++++++++++++++++++++++++++++++++++-
 controller/mac_cache.h      |  27 +++++++
 controller/ovn-controller.c | 115 ++++++++++++++++++++++++++++--
 3 files changed, 274 insertions(+), 6 deletions(-)

diff --git a/controller/mac_cache.c b/controller/mac_cache.c
index c89de6b24..a8fc272a1 100644
--- a/controller/mac_cache.c
+++ b/controller/mac_cache.c
@@ -37,6 +37,17 @@ static bool
 mac_cache_mb_data_from_sbrec(struct mac_cache_mb_data *data,
                               const struct sbrec_mac_binding *mb,
                               struct ovsdb_idl_index *sbrec_pb_by_name);
+static uint32_t
+mac_cache_fdb_data_hash(const struct mac_cache_fdb_data *fdb_data);
+static inline bool
+mac_cache_fdb_data_equals(const struct mac_cache_fdb_data *a,
+                          const struct mac_cache_fdb_data *b);
+static bool
+mac_cache_fdb_data_from_sbrec(struct mac_cache_fdb_data *data,
+                              const struct sbrec_fdb *fdb);
+static struct mac_cache_fdb *
+mac_cache_fdb_find(struct mac_cache_data *data,
+                   const struct mac_cache_fdb_data *fdb_data);
 static struct mac_cache_threshold *
 mac_cache_threshold_find(struct hmap *thresholds, const struct uuid *uuid);
 static uint64_t
@@ -169,6 +180,70 @@ mac_cache_mac_bindings_clear(struct mac_cache_data *data)
     }
 }
 
+void
+mac_cache_fdb_add(struct mac_cache_data *data, const struct sbrec_fdb *fdb,
+                  struct uuid dp_uuid)
+{
+    struct mac_cache_fdb_data fdb_data;
+    if (!mac_cache_fdb_data_from_sbrec(&fdb_data, fdb)) {
+        return;
+    }
+
+    struct mac_cache_fdb *mc_fdb = mac_cache_fdb_find(data, &fdb_data);
+
+    if (!mc_fdb) {
+        mc_fdb = xmalloc(sizeof *mc_fdb);
+        hmap_insert(&data->fdbs, &mc_fdb->hmap_node,
+                    mac_cache_fdb_data_hash(&fdb_data));
+    }
+
+    mc_fdb->sbrec_fdb = fdb;
+    mc_fdb->data = fdb_data;
+    mc_fdb->dp_uuid = dp_uuid;
+}
+
+void
+mac_cache_fdb_remove(struct mac_cache_data *data, const struct sbrec_fdb *fdb)
+{
+    struct mac_cache_fdb_data fdb_data;
+    if (!mac_cache_fdb_data_from_sbrec(&fdb_data, fdb)) {
+        return;
+    }
+
+    struct mac_cache_fdb *mc_fdb = mac_cache_fdb_find(data, &fdb_data);
+    if (!mc_fdb) {
+        return;
+    }
+
+    hmap_remove(&data->fdbs, &mc_fdb->hmap_node);
+    free(mc_fdb);
+}
+
+bool
+mac_cache_sb_fdb_updated(const struct sbrec_fdb *fdb)
+{
+    bool updated = false;
+    for (size_t i = 0; i < SBREC_FDB_N_COLUMNS; i++) {
+        /* Ignore timestamp update as this does not affect the existing nodes
+         * at all. */
+        if (i == SBREC_FDB_COL_TIMESTAMP) {
+            continue;
+        }
+        updated |= sbrec_fdb_is_updated(fdb, i);
+    }
+
+    return updated || sbrec_fdb_is_deleted(fdb);
+}
+
+void
+mac_cache_fdbs_clear(struct mac_cache_data *data)
+{
+    struct mac_cache_fdb *mc_fdb;
+    HMAP_FOR_EACH_POP (mc_fdb, hmap_node, &data->fdbs) {
+        free(mc_fdb);
+    }
+}
+
 struct mac_cache_stats {
     struct ovs_list list_node;
 
@@ -177,6 +252,8 @@ struct mac_cache_stats {
     union {
         /* Common data to identify MAC binding. */
         struct mac_cache_mb_data mb;
+        /* Common data to identify FDB. */
+        struct mac_cache_fdb_data fdb;
     } data;
 };
 
@@ -308,6 +385,60 @@ mac_cache_mac_binding_find(struct mac_cache_data *data,
     return NULL;
 }
 
+static uint32_t
+mac_cache_fdb_data_hash(const struct mac_cache_fdb_data *fdb_data)
+{
+    uint32_t hash = 0;
+
+    hash = hash_add(hash, fdb_data->port_key);
+    hash = hash_add(hash, fdb_data->dp_key);
+    hash = hash_add64(hash, eth_addr_to_uint64(fdb_data->mac));
+
+    return hash_finish(hash, 16);
+}
+
+static inline bool
+mac_cache_fdb_data_equals(const struct mac_cache_fdb_data *a,
+                          const struct mac_cache_fdb_data *b)
+{
+    return a->port_key == b->port_key &&
+           a->dp_key == b->dp_key &&
+           eth_addr_equals(a->mac, b->mac);
+}
+
+static bool
+mac_cache_fdb_data_from_sbrec(struct mac_cache_fdb_data *data,
+                              const struct sbrec_fdb *fdb)
+{
+
+    if (!eth_addr_from_string(fdb->mac, &data->mac)) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+        VLOG_WARN_RL(&rl, "Couldn't parse FDB: mac=%s", fdb->mac);
+        return false;
+    }
+
+    data->dp_key = fdb->dp_key;
+    data->port_key = fdb->port_key;
+
+    return true;
+}
+
+static struct mac_cache_fdb *
+mac_cache_fdb_find(struct mac_cache_data *data,
+                   const struct mac_cache_fdb_data *fdb_data)
+{
+    uint32_t hash = mac_cache_fdb_data_hash(fdb_data);
+
+    struct mac_cache_fdb *fdb;
+    HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, &data->fdbs) {
+        if (mac_cache_fdb_data_equals(&fdb->data, fdb_data)) {
+            return fdb;
+        }
+    }
+
+    return NULL;
+}
+
 static struct mac_cache_threshold *
 mac_cache_threshold_find(struct hmap *thresholds, const struct uuid *uuid)
 {
@@ -330,8 +461,11 @@ mac_cache_threshold_get_value_ms(const struct 
sbrec_datapath_binding *dp,
     uint64_t value = 0;
     switch (type) {
     case MAC_CACHE_MAC_BINDING:
-        value = smap_get_uint(&dp->external_ids,
-                              "mac_binding_age_threshold", 0);
+        value = smap_get_uint(&dp->external_ids, "mac_binding_age_threshold",
+                              0);
+        break;
+    case MAC_CACHE_FDB:
+        value = smap_get_uint(&dp->external_ids, "fdb_age_threshold", 0);
         break;
     case MAC_CACHE_MAX:
     default:
diff --git a/controller/mac_cache.h b/controller/mac_cache.h
index 2a3dc66f0..7bde84564 100644
--- a/controller/mac_cache.h
+++ b/controller/mac_cache.h
@@ -24,6 +24,7 @@
 
 enum mac_cache_type {
     MAC_CACHE_MAC_BINDING,
+    MAC_CACHE_FDB,
     MAC_CACHE_MAX
 };
 
@@ -33,6 +34,9 @@ struct mac_cache_data {
     /* 'struct mac_cache_mac_binding' by 'struct mac_cache_mb_data' that are
      * local and have threshold > 0. */
     struct hmap mac_bindings;
+    /* 'struct mac_cache_fdb' by 'struct mac_cache_fdb_data' that are
+     * local and have threshold > 0. */
+    struct hmap fdbs;
 };
 
 struct mac_cache_threshold {
@@ -60,6 +64,22 @@ struct mac_cache_mac_binding {
     const struct sbrec_mac_binding *sbrec_mb;
 };
 
+struct mac_cache_fdb_data {
+    uint32_t port_key;
+    uint32_t dp_key;
+    struct eth_addr mac;
+};
+
+struct mac_cache_fdb {
+    struct hmap_node hmap_node;
+    /* Common data to identify FDB. */
+    struct mac_cache_fdb_data data;
+    /* Reference to the SB FDB record. */
+    const struct sbrec_fdb *sbrec_fdb;
+    /* UUID of datapath for this FDB record. */
+    struct uuid dp_uuid;
+};
+
 bool mac_cache_threshold_add(struct mac_cache_data *data,
                              const struct sbrec_datapath_binding *dp,
                              enum mac_cache_type type);
@@ -80,6 +100,13 @@ void mac_cache_mac_binding_remove(struct mac_cache_data 
*data,
 void mac_cache_mac_bindings_clear(struct mac_cache_data *data);
 bool mac_cache_sb_mac_binding_updated(const struct sbrec_mac_binding *mb);
 
+void mac_cache_fdb_add(struct mac_cache_data *data,
+                       const struct sbrec_fdb *fdb, struct uuid dp_uuid);
+void mac_cache_fdb_remove(struct mac_cache_data *data,
+                          const struct sbrec_fdb *fdb);
+bool mac_cache_sb_fdb_updated(const struct sbrec_fdb *fdb);
+void mac_cache_fdbs_clear(struct mac_cache_data *data);
+
 void
 mac_cache_mb_stats_process_flow_stats(struct ovs_list *stats_list,
                                       struct ofputil_flow_stats *ofp_stats);
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index f050571f0..1911da416 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -3263,6 +3263,29 @@ mac_cache_mb_handle_for_datapath(struct mac_cache_data 
*data,
     sbrec_mac_binding_index_destroy_row(mb_index_row);
 }
 
+static void
+mac_cache_fdb_handle_for_datapath(struct mac_cache_data *data,
+                                  const struct sbrec_datapath_binding *dp,
+                                  struct ovsdb_idl_index *sbrec_fdb_by_dp_key)
+{
+    bool has_threshold = mac_cache_threshold_replace(data, dp, MAC_CACHE_FDB);
+
+    struct sbrec_fdb *fdb_index_row =
+            sbrec_fdb_index_init_row(sbrec_fdb_by_dp_key);
+    sbrec_fdb_set_dp_key(fdb_index_row, dp->tunnel_key);
+
+    const struct sbrec_fdb *fdb;
+    SBREC_FDB_FOR_EACH_EQUAL (fdb, fdb_index_row, sbrec_fdb_by_dp_key) {
+        if (has_threshold) {
+            mac_cache_fdb_add(data, fdb, dp->header_.uuid);
+        } else {
+            mac_cache_fdb_remove(data, fdb);
+        }
+    }
+
+    sbrec_fdb_index_destroy_row(fdb_index_row);
+}
+
 static void *
 en_mac_cache_init(struct engine_node *node OVS_UNUSED,
                    struct engine_arg *arg OVS_UNUSED)
@@ -3273,6 +3296,7 @@ en_mac_cache_init(struct engine_node *node OVS_UNUSED,
         hmap_init(&cache_data->thresholds[i]);
     }
     hmap_init(&cache_data->mac_bindings);
+    hmap_init(&cache_data->fdbs);
 
     return cache_data;
 }
@@ -3285,6 +3309,8 @@ en_mac_cache_run(struct engine_node *node, void *data)
             engine_get_input_data("runtime_data", node);
     const struct sbrec_mac_binding_table *mb_table =
             EN_OVSDB_GET(engine_get_input("SB_mac_binding", node));
+    const struct sbrec_fdb_table *fdb_table =
+            EN_OVSDB_GET(engine_get_input("SB_fdb", node));
     struct ovsdb_idl_index *sbrec_pb_by_name =
             engine_ovsdb_node_get_index(
                     engine_get_input("SB_port_binding", node),
@@ -3292,6 +3318,7 @@ en_mac_cache_run(struct engine_node *node, void *data)
 
     mac_cache_thresholds_clear(cache_data);
     mac_cache_mac_bindings_clear(cache_data);
+    mac_cache_fdbs_clear(cache_data);
 
     const struct sbrec_mac_binding *sbrec_mb;
     SBREC_MAC_BINDING_TABLE_FOR_EACH (sbrec_mb, mb_table) {
@@ -3306,6 +3333,22 @@ en_mac_cache_run(struct engine_node *node, void *data)
         }
     }
 
+    struct local_datapath *local_dp;
+    const struct sbrec_fdb *sbrec_fdb;
+    SBREC_FDB_TABLE_FOR_EACH (sbrec_fdb, fdb_table) {
+        local_dp = get_local_datapath(&rt_data->local_datapaths,
+                                      sbrec_fdb->dp_key);
+        if (!local_dp) {
+            continue;
+        }
+
+        if (mac_cache_threshold_add(cache_data, local_dp->datapath,
+                                    MAC_CACHE_FDB)) {
+            mac_cache_fdb_add(cache_data, sbrec_fdb,
+                              local_dp->datapath->header_.uuid);
+        }
+    }
+
     engine_set_node_state(node, EN_UPDATED);
 }
 
@@ -3354,6 +3397,48 @@ mac_cache_sb_mac_binding_handler(struct engine_node 
*node, void *data)
     return true;
 }
 
+static bool
+mac_cache_sb_fdb_handler(struct engine_node *node, void *data)
+{
+    struct mac_cache_data *cache_data = data;
+    struct ed_type_runtime_data *rt_data =
+            engine_get_input_data("runtime_data", node);
+    const struct sbrec_fdb_table *fdb_table =
+            EN_OVSDB_GET(engine_get_input("SB_fdb", node));
+
+    size_t previous_size = hmap_count(&cache_data->fdbs);
+
+    struct local_datapath *local_dp;
+    const struct sbrec_fdb *sbrec_fdb;
+    SBREC_FDB_TABLE_FOR_EACH_TRACKED (sbrec_fdb, fdb_table) {
+        if (!mac_cache_sb_fdb_updated(sbrec_fdb)) {
+            continue;
+        }
+
+        if (!sbrec_fdb_is_new(sbrec_fdb)) {
+            mac_cache_fdb_remove(cache_data, sbrec_fdb);
+        }
+
+        local_dp = get_local_datapath(&rt_data->local_datapaths,
+                                      sbrec_fdb->dp_key);
+        if (sbrec_fdb_is_deleted(sbrec_fdb) || !local_dp) {
+            continue;
+        }
+
+        if (mac_cache_threshold_add(cache_data, local_dp->datapath,
+                                    MAC_CACHE_FDB)) {
+            mac_cache_fdb_add(cache_data, sbrec_fdb,
+                              local_dp->datapath->header_.uuid);
+        }
+    }
+
+    if (hmap_count(&cache_data->fdbs) != previous_size) {
+        engine_set_node_state(node, EN_UPDATED);
+    }
+
+    return true;
+}
+
 static bool
 mac_cache_runtime_data_handler(struct engine_node *node, void *data OVS_UNUSED)
 {
@@ -3368,13 +3453,18 @@ mac_cache_runtime_data_handler(struct engine_node 
*node, void *data OVS_UNUSED)
             engine_ovsdb_node_get_index(
                     engine_get_input("SB_port_binding", node),
                     "name");
+    struct ovsdb_idl_index *sbrec_fdb_by_dp_key =
+            engine_ovsdb_node_get_index(
+                    engine_get_input("SB_fdb", node),
+                    "dp_key");
 
     /* There are no tracked data. Fall back to full recompute. */
     if (!rt_data->tracked) {
         return false;
     }
 
-    size_t previous_size = hmap_count(&cache_data->mac_bindings);
+    size_t previous_mb_size = hmap_count(&cache_data->mac_bindings);
+    size_t previous_fdb_size = hmap_count(&cache_data->fdbs);
 
     struct tracked_datapath *tdp;
     HMAP_FOR_EACH (tdp, node, &rt_data->tracked_dp_bindings) {
@@ -3384,9 +3474,13 @@ mac_cache_runtime_data_handler(struct engine_node *node, 
void *data OVS_UNUSED)
 
         mac_cache_mb_handle_for_datapath(cache_data, tdp->dp,
                                          sbrec_mb_by_dp, sbrec_pb_by_name);
+
+        mac_cache_fdb_handle_for_datapath(cache_data, tdp->dp,
+                                          sbrec_fdb_by_dp_key);
     }
 
-    if (hmap_count(&cache_data->mac_bindings) != previous_size) {
+    if (hmap_count(&cache_data->mac_bindings) != previous_mb_size ||
+        hmap_count(&cache_data->fdbs) != previous_fdb_size) {
         engine_set_node_state(node, EN_UPDATED);
     }
 
@@ -3409,8 +3503,13 @@ mac_cache_sb_datapath_binding_handler(struct engine_node 
*node, void *data)
             engine_ovsdb_node_get_index(
                     engine_get_input("SB_port_binding", node),
                     "name");
+    struct ovsdb_idl_index *sbrec_fdb_by_dp_key =
+            engine_ovsdb_node_get_index(
+                    engine_get_input("SB_fdb", node),
+                    "dp_key");
 
-    size_t previous_size = hmap_count(&cache_data->mac_bindings);
+    size_t previous_mb_size = hmap_count(&cache_data->mac_bindings);
+    size_t previous_fdb_size = hmap_count(&cache_data->fdbs);
 
     const struct sbrec_datapath_binding *sbrec_dp;
     SBREC_DATAPATH_BINDING_TABLE_FOR_EACH (sbrec_dp, dp_table) {
@@ -3423,9 +3522,13 @@ mac_cache_sb_datapath_binding_handler(struct engine_node 
*node, void *data)
 
         mac_cache_mb_handle_for_datapath(cache_data, sbrec_dp,
                                          sbrec_mb_by_dp, sbrec_pb_by_name);
+
+        mac_cache_fdb_handle_for_datapath(cache_data, sbrec_dp,
+                                          sbrec_fdb_by_dp_key);
     }
 
-    if (hmap_count(&cache_data->mac_bindings) != previous_size) {
+    if (hmap_count(&cache_data->mac_bindings) != previous_mb_size ||
+        hmap_count(&cache_data->fdbs) != previous_fdb_size) {
         engine_set_node_state(node, EN_UPDATED);
     }
 
@@ -3444,6 +3547,8 @@ en_mac_cache_cleanup(void *data)
     }
     mac_cache_mac_bindings_clear(cache_data);
     hmap_destroy(&cache_data->mac_bindings);
+    mac_cache_fdbs_clear(cache_data);
+    hmap_destroy(&cache_data->fdbs);
 }
 
 /* Engine node which is used to handle the Non VIF data like
@@ -5241,6 +5346,8 @@ main(int argc, char *argv[])
                      mac_cache_runtime_data_handler);
     engine_add_input(&en_mac_cache, &en_sb_mac_binding,
                      mac_cache_sb_mac_binding_handler);
+    engine_add_input(&en_mac_cache, &en_sb_fdb,
+                     mac_cache_sb_fdb_handler);
     engine_add_input(&en_mac_cache, &en_sb_datapath_binding,
                      mac_cache_sb_datapath_binding_handler);
     engine_add_input(&en_mac_cache, &en_sb_port_binding,
-- 
2.41.0

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

Reply via email to