Commit fa81d6d2 authored by Louis Peens's avatar Louis Peens Committed by David S. Miller
Browse files

nfp: flower-ct: add a table to map flow cookies to ct flows



Add a hashtable which contains entries to map flow cookies to ct
flow entries. Currently the entries are added and not used, but
follow-up patches will use this for stats updates and flow deletes.

Signed-off-by: default avatarLouis Peens <louis.peens@corigine.com>
Signed-off-by: default avatarYinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 072c089c
Loading
Loading
Loading
Loading
+29 −6
Original line number Diff line number Diff line
@@ -107,9 +107,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;

@@ -160,12 +162,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:
@@ -245,7 +268,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;
@@ -286,7 +309,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);

+13 −0
Original line number Diff line number Diff line
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -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;
};

/**
+45 −1
Original line number Diff line number Diff line
@@ -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);