OSDN Git Service

nfp: flower-ct: add a table to map flow cookies to ct flows
authorLouis Peens <louis.peens@corigine.com>
Wed, 2 Jun 2021 11:59:50 +0000 (13:59 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jun 2021 21:04:42 +0000 (14:04 -0700)
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: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Yinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/flower/conntrack.c
drivers/net/ethernet/netronome/nfp/flower/conntrack.h
drivers/net/ethernet/netronome/nfp/flower/main.h
drivers/net/ethernet/netronome/nfp/flower/metadata.c

index 57a5ba5..f6f9722 100644 (file)
@@ -107,9 +107,11 @@ err_zone_insert:
 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);
 
index 46437de..a7f0d7c 100644 (file)
@@ -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);
 
index 060c6de..0fbd682 100644 (file)
@@ -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;
 };
 
 /**
index 062e963..7654cf6 100644 (file)
@@ -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 @@ err_free_last_used:
        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);