@@ -106,9 +106,11 @@ nfp_fl_ct_zone_entry *get_nfp_zone_entry(struct nfp_flower_priv *priv,
static struct
nfp_fl_ct_flow_entry *nfp_fl_ct_add_flow(struct nfp_fl_ct_zone_entry *zt,
struct net_device *netdev,
- struct flow_cls_offload *flow)
+ struct flow_cls_offload *flow,
+ struct netlink_ext_ack *extack)
{
struct nfp_fl_ct_flow_entry *entry;
+ struct nfp_fl_ct_map_entry *map;
struct flow_action_entry *act;
int err, i;
@@ -159,12 +161,33 @@ nfp_fl_ct_flow_entry *nfp_fl_ct_add_flow(struct nfp_fl_ct_zone_entry *zt,
INIT_LIST_HEAD(&entry->children);
- /* Creation of a ct_map_entry and adding it to a hashtable
- * will happen here in follow up patches.
- */
+ /* Now add a ct map entry to flower-priv */
+ map = get_hashentry(&zt->priv->ct_map_table, &flow->cookie,
+ nfp_ct_map_params, sizeof(*map));
+ if (IS_ERR(map)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: ct map entry creation failed");
+ err = -ENOMEM;
+ goto err_ct_flow_insert;
+ }
+ map->cookie = flow->cookie;
+ map->ct_entry = entry;
+ err = rhashtable_insert_fast(&zt->priv->ct_map_table,
+ &map->hash_node,
+ nfp_ct_map_params);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: ct map entry table add failed");
+ goto err_map_insert;
+ }
return entry;
+err_map_insert:
+ kfree(map);
+err_ct_flow_insert:
+ if (entry->tun_offset != NFP_FL_CT_NO_TUN)
+ kfree(entry->rule->action.entries[entry->tun_offset].tunnel);
err_pre_ct_tun_cp:
kfree(entry->rule);
err_pre_ct_act:
@@ -244,7 +267,7 @@ int nfp_fl_ct_handle_pre_ct(struct nfp_flower_priv *priv,
zt->nft = ct_act->ct.flow_table;
/* Add entry to pre_ct_list */
- ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow);
+ ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, extack);
if (IS_ERR(ct_entry))
return PTR_ERR(ct_entry);
ct_entry->type = CT_TYPE_PRE_CT;
@@ -285,7 +308,7 @@ int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
}
/* Add entry to post_ct_list */
- ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow);
+ ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, extack);
if (IS_ERR(ct_entry))
return PTR_ERR(ct_entry);
@@ -9,6 +9,7 @@
#define NFP_FL_CT_NO_TUN 0xff
extern const struct rhashtable_params nfp_zone_table_params;
+extern const struct rhashtable_params nfp_ct_map_params;
/**
* struct nfp_fl_ct_zone_entry - Zone entry containing conntrack flow information
@@ -69,6 +70,18 @@ struct nfp_fl_ct_flow_entry {
u8 tun_offset; // Set to NFP_FL_CT_NO_TUN if no tun
};
+/**
+ * struct nfp_fl_ct_map_entry - Map between flow cookie and specific ct_flow
+ * @cookie: Flow cookie, same as original TC flow, used as key
+ * @hash_node: Used by the hashtable
+ * @ct_entry: Pointer to corresponding ct_entry
+ */
+struct nfp_fl_ct_map_entry {
+ unsigned long cookie;
+ struct rhash_head hash_node;
+ struct nfp_fl_ct_flow_entry *ct_entry;
+};
+
bool is_pre_ct_flow(struct flow_cls_offload *flow);
bool is_post_ct_flow(struct flow_cls_offload *flow);
@@ -195,6 +195,7 @@ struct nfp_fl_internal_ports {
* @merge_table: Hash table to store merged flows
* @ct_zone_table: Hash table used to store the different zones
* @ct_zone_wc: Special zone entry for wildcarded zone matches
+ * @ct_map_table: Hash table used to referennce ct flows
*/
struct nfp_flower_priv {
struct nfp_app *app;
@@ -231,6 +232,7 @@ struct nfp_flower_priv {
struct rhashtable merge_table;
struct rhashtable ct_zone_table;
struct nfp_fl_ct_zone_entry *ct_zone_wc;
+ struct rhashtable ct_map_table;
};
/**
@@ -504,6 +504,13 @@ const struct rhashtable_params nfp_zone_table_params = {
.automatic_shrinking = false,
};
+const struct rhashtable_params nfp_ct_map_params = {
+ .head_offset = offsetof(struct nfp_fl_ct_map_entry, hash_node),
+ .key_len = sizeof(unsigned long),
+ .key_offset = offsetof(struct nfp_fl_ct_map_entry, cookie),
+ .automatic_shrinking = true,
+};
+
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
unsigned int host_num_mems)
{
@@ -528,6 +535,10 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
if (err)
goto err_free_merge_table;
+ err = rhashtable_init(&priv->ct_map_table, &nfp_ct_map_params);
+ if (err)
+ goto err_free_ct_zone_table;
+
get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
/* Init ring buffer and unallocated mask_ids. */
@@ -535,7 +546,7 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
if (!priv->mask_ids.mask_id_free_list.buf)
- goto err_free_ct_zone_table;
+ goto err_free_ct_map_table;
priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
@@ -572,6 +583,8 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
kfree(priv->mask_ids.last_used);
err_free_mask_id:
kfree(priv->mask_ids.mask_id_free_list.buf);
+err_free_ct_map_table:
+ rhashtable_destroy(&priv->ct_map_table);
err_free_ct_zone_table:
rhashtable_destroy(&priv->ct_zone_table);
err_free_merge_table:
@@ -589,22 +602,40 @@ static void nfp_zone_table_entry_destroy(struct nfp_fl_ct_zone_entry *zt)
return;
if (!list_empty(&zt->pre_ct_list)) {
+ struct rhashtable *m_table = &zt->priv->ct_map_table;
struct nfp_fl_ct_flow_entry *entry, *tmp;
+ struct nfp_fl_ct_map_entry *map;
WARN_ONCE(1, "pre_ct_list not empty as expected, cleaning up\n");
list_for_each_entry_safe(entry, tmp, &zt->pre_ct_list,
list_node) {
+ map = rhashtable_lookup_fast(m_table,
+ &entry->cookie,
+ nfp_ct_map_params);
+ WARN_ON_ONCE(rhashtable_remove_fast(m_table,
+ &map->hash_node,
+ nfp_ct_map_params));
nfp_fl_ct_clean_flow_entry(entry);
+ kfree(map);
}
}
if (!list_empty(&zt->post_ct_list)) {
+ struct rhashtable *m_table = &zt->priv->ct_map_table;
struct nfp_fl_ct_flow_entry *entry, *tmp;
+ struct nfp_fl_ct_map_entry *map;
WARN_ONCE(1, "post_ct_list not empty as expected, cleaning up\n");
list_for_each_entry_safe(entry, tmp, &zt->post_ct_list,
list_node) {
+ map = rhashtable_lookup_fast(m_table,
+ &entry->cookie,
+ nfp_ct_map_params);
+ WARN_ON_ONCE(rhashtable_remove_fast(m_table,
+ &map->hash_node,
+ nfp_ct_map_params));
nfp_fl_ct_clean_flow_entry(entry);
+ kfree(map);
}
}
kfree(zt);
@@ -617,6 +648,16 @@ static void nfp_free_zone_table_entry(void *ptr, void *arg)
nfp_zone_table_entry_destroy(zt);
}
+static void nfp_free_map_table_entry(void *ptr, void *arg)
+{
+ struct nfp_fl_ct_map_entry *map = ptr;
+
+ if (!map)
+ return;
+
+ kfree(map);
+}
+
void nfp_flower_metadata_cleanup(struct nfp_app *app)
{
struct nfp_flower_priv *priv = app->priv;
@@ -633,6 +674,9 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app)
rhashtable_free_and_destroy(&priv->ct_zone_table,
nfp_free_zone_table_entry, NULL);
nfp_zone_table_entry_destroy(priv->ct_zone_wc);
+
+ rhashtable_free_and_destroy(&priv->ct_map_table,
+ nfp_free_map_table_entry, NULL);
kvfree(priv->stats);
kfree(priv->mask_ids.mask_id_free_list.buf);
kfree(priv->mask_ids.last_used);