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
