|
@@ -48,6 +48,12 @@ struct nfp_mask_id_table {
|
|
u8 mask_id;
|
|
u8 mask_id;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct nfp_fl_flow_table_cmp_arg {
|
|
|
|
+ struct net_device *netdev;
|
|
|
|
+ unsigned long cookie;
|
|
|
|
+ __be32 host_ctx;
|
|
|
|
+};
|
|
|
|
+
|
|
static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id)
|
|
static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id)
|
|
{
|
|
{
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
@@ -55,14 +61,14 @@ static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id)
|
|
|
|
|
|
ring = &priv->stats_ids.free_list;
|
|
ring = &priv->stats_ids.free_list;
|
|
/* Check if buffer is full. */
|
|
/* Check if buffer is full. */
|
|
- if (!CIRC_SPACE(ring->head, ring->tail, NFP_FL_STATS_ENTRY_RS *
|
|
|
|
- NFP_FL_STATS_ELEM_RS -
|
|
|
|
|
|
+ if (!CIRC_SPACE(ring->head, ring->tail,
|
|
|
|
+ priv->stats_ring_size * NFP_FL_STATS_ELEM_RS -
|
|
NFP_FL_STATS_ELEM_RS + 1))
|
|
NFP_FL_STATS_ELEM_RS + 1))
|
|
return -ENOBUFS;
|
|
return -ENOBUFS;
|
|
|
|
|
|
memcpy(&ring->buf[ring->head], &stats_context_id, NFP_FL_STATS_ELEM_RS);
|
|
memcpy(&ring->buf[ring->head], &stats_context_id, NFP_FL_STATS_ELEM_RS);
|
|
ring->head = (ring->head + NFP_FL_STATS_ELEM_RS) %
|
|
ring->head = (ring->head + NFP_FL_STATS_ELEM_RS) %
|
|
- (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);
|
|
|
|
|
|
+ (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -74,7 +80,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id)
|
|
struct circ_buf *ring;
|
|
struct circ_buf *ring;
|
|
|
|
|
|
ring = &priv->stats_ids.free_list;
|
|
ring = &priv->stats_ids.free_list;
|
|
- freed_stats_id = NFP_FL_STATS_ENTRY_RS;
|
|
|
|
|
|
+ freed_stats_id = priv->stats_ring_size;
|
|
/* Check for unallocated entries first. */
|
|
/* Check for unallocated entries first. */
|
|
if (priv->stats_ids.init_unalloc > 0) {
|
|
if (priv->stats_ids.init_unalloc > 0) {
|
|
*stats_context_id = priv->stats_ids.init_unalloc - 1;
|
|
*stats_context_id = priv->stats_ids.init_unalloc - 1;
|
|
@@ -92,7 +98,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id)
|
|
*stats_context_id = temp_stats_id;
|
|
*stats_context_id = temp_stats_id;
|
|
memcpy(&ring->buf[ring->tail], &freed_stats_id, NFP_FL_STATS_ELEM_RS);
|
|
memcpy(&ring->buf[ring->tail], &freed_stats_id, NFP_FL_STATS_ELEM_RS);
|
|
ring->tail = (ring->tail + NFP_FL_STATS_ELEM_RS) %
|
|
ring->tail = (ring->tail + NFP_FL_STATS_ELEM_RS) %
|
|
- (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);
|
|
|
|
|
|
+ (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -102,56 +108,37 @@ struct nfp_fl_payload *
|
|
nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie,
|
|
nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie,
|
|
struct net_device *netdev, __be32 host_ctx)
|
|
struct net_device *netdev, __be32 host_ctx)
|
|
{
|
|
{
|
|
|
|
+ struct nfp_fl_flow_table_cmp_arg flower_cmp_arg;
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
- struct nfp_fl_payload *flower_entry;
|
|
|
|
|
|
|
|
- hash_for_each_possible_rcu(priv->flow_table, flower_entry, link,
|
|
|
|
- tc_flower_cookie)
|
|
|
|
- if (flower_entry->tc_flower_cookie == tc_flower_cookie &&
|
|
|
|
- (!netdev || flower_entry->ingress_dev == netdev) &&
|
|
|
|
- (host_ctx == NFP_FL_STATS_CTX_DONT_CARE ||
|
|
|
|
- flower_entry->meta.host_ctx_id == host_ctx))
|
|
|
|
- return flower_entry;
|
|
|
|
|
|
+ flower_cmp_arg.netdev = netdev;
|
|
|
|
+ flower_cmp_arg.cookie = tc_flower_cookie;
|
|
|
|
+ flower_cmp_arg.host_ctx = host_ctx;
|
|
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void
|
|
|
|
-nfp_flower_update_stats(struct nfp_app *app, struct nfp_fl_stats_frame *stats)
|
|
|
|
-{
|
|
|
|
- struct nfp_fl_payload *nfp_flow;
|
|
|
|
- unsigned long flower_cookie;
|
|
|
|
-
|
|
|
|
- flower_cookie = be64_to_cpu(stats->stats_cookie);
|
|
|
|
-
|
|
|
|
- rcu_read_lock();
|
|
|
|
- nfp_flow = nfp_flower_search_fl_table(app, flower_cookie, NULL,
|
|
|
|
- stats->stats_con_id);
|
|
|
|
- if (!nfp_flow)
|
|
|
|
- goto exit_rcu_unlock;
|
|
|
|
-
|
|
|
|
- spin_lock(&nfp_flow->lock);
|
|
|
|
- nfp_flow->stats.pkts += be32_to_cpu(stats->pkt_count);
|
|
|
|
- nfp_flow->stats.bytes += be64_to_cpu(stats->byte_count);
|
|
|
|
- nfp_flow->stats.used = jiffies;
|
|
|
|
- spin_unlock(&nfp_flow->lock);
|
|
|
|
-
|
|
|
|
-exit_rcu_unlock:
|
|
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ return rhashtable_lookup_fast(&priv->flow_table, &flower_cmp_arg,
|
|
|
|
+ nfp_flower_table_params);
|
|
}
|
|
}
|
|
|
|
|
|
void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb)
|
|
void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb)
|
|
{
|
|
{
|
|
unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
|
|
unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
|
|
- struct nfp_fl_stats_frame *stats_frame;
|
|
|
|
|
|
+ struct nfp_flower_priv *priv = app->priv;
|
|
|
|
+ struct nfp_fl_stats_frame *stats;
|
|
unsigned char *msg;
|
|
unsigned char *msg;
|
|
|
|
+ u32 ctx_id;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
msg = nfp_flower_cmsg_get_data(skb);
|
|
msg = nfp_flower_cmsg_get_data(skb);
|
|
|
|
|
|
- stats_frame = (struct nfp_fl_stats_frame *)msg;
|
|
|
|
- for (i = 0; i < msg_len / sizeof(*stats_frame); i++)
|
|
|
|
- nfp_flower_update_stats(app, stats_frame + i);
|
|
|
|
|
|
+ spin_lock(&priv->stats_lock);
|
|
|
|
+ for (i = 0; i < msg_len / sizeof(*stats); i++) {
|
|
|
|
+ stats = (struct nfp_fl_stats_frame *)msg + i;
|
|
|
|
+ ctx_id = be32_to_cpu(stats->stats_con_id);
|
|
|
|
+ priv->stats[ctx_id].pkts += be32_to_cpu(stats->pkt_count);
|
|
|
|
+ priv->stats[ctx_id].bytes += be64_to_cpu(stats->byte_count);
|
|
|
|
+ priv->stats[ctx_id].used = jiffies;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&priv->stats_lock);
|
|
}
|
|
}
|
|
|
|
|
|
static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id)
|
|
static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id)
|
|
@@ -345,9 +332,9 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
|
|
|
|
|
|
/* Update flow payload with mask ids. */
|
|
/* Update flow payload with mask ids. */
|
|
nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;
|
|
nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;
|
|
- nfp_flow->stats.pkts = 0;
|
|
|
|
- nfp_flow->stats.bytes = 0;
|
|
|
|
- nfp_flow->stats.used = jiffies;
|
|
|
|
|
|
+ priv->stats[stats_cxt].pkts = 0;
|
|
|
|
+ priv->stats[stats_cxt].bytes = 0;
|
|
|
|
+ priv->stats[stats_cxt].used = jiffies;
|
|
|
|
|
|
check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev,
|
|
check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev,
|
|
NFP_FL_STATS_CTX_DONT_CARE);
|
|
NFP_FL_STATS_CTX_DONT_CARE);
|
|
@@ -389,12 +376,56 @@ int nfp_modify_flow_metadata(struct nfp_app *app,
|
|
return nfp_release_stats_entry(app, temp_ctx_id);
|
|
return nfp_release_stats_entry(app, temp_ctx_id);
|
|
}
|
|
}
|
|
|
|
|
|
-int nfp_flower_metadata_init(struct nfp_app *app)
|
|
|
|
|
|
+static int nfp_fl_obj_cmpfn(struct rhashtable_compare_arg *arg,
|
|
|
|
+ const void *obj)
|
|
|
|
+{
|
|
|
|
+ const struct nfp_fl_flow_table_cmp_arg *cmp_arg = arg->key;
|
|
|
|
+ const struct nfp_fl_payload *flow_entry = obj;
|
|
|
|
+
|
|
|
|
+ if ((!cmp_arg->netdev || flow_entry->ingress_dev == cmp_arg->netdev) &&
|
|
|
|
+ (cmp_arg->host_ctx == NFP_FL_STATS_CTX_DONT_CARE ||
|
|
|
|
+ flow_entry->meta.host_ctx_id == cmp_arg->host_ctx))
|
|
|
|
+ return flow_entry->tc_flower_cookie != cmp_arg->cookie;
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 nfp_fl_obj_hashfn(const void *data, u32 len, u32 seed)
|
|
|
|
+{
|
|
|
|
+ const struct nfp_fl_payload *flower_entry = data;
|
|
|
|
+
|
|
|
|
+ return jhash2((u32 *)&flower_entry->tc_flower_cookie,
|
|
|
|
+ sizeof(flower_entry->tc_flower_cookie) / sizeof(u32),
|
|
|
|
+ seed);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 nfp_fl_key_hashfn(const void *data, u32 len, u32 seed)
|
|
|
|
+{
|
|
|
|
+ const struct nfp_fl_flow_table_cmp_arg *cmp_arg = data;
|
|
|
|
+
|
|
|
|
+ return jhash2((u32 *)&cmp_arg->cookie,
|
|
|
|
+ sizeof(cmp_arg->cookie) / sizeof(u32), seed);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const struct rhashtable_params nfp_flower_table_params = {
|
|
|
|
+ .head_offset = offsetof(struct nfp_fl_payload, fl_node),
|
|
|
|
+ .hashfn = nfp_fl_key_hashfn,
|
|
|
|
+ .obj_cmpfn = nfp_fl_obj_cmpfn,
|
|
|
|
+ .obj_hashfn = nfp_fl_obj_hashfn,
|
|
|
|
+ .automatic_shrinking = true,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count)
|
|
{
|
|
{
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
struct nfp_flower_priv *priv = app->priv;
|
|
|
|
+ int err;
|
|
|
|
|
|
hash_init(priv->mask_table);
|
|
hash_init(priv->mask_table);
|
|
- hash_init(priv->flow_table);
|
|
|
|
|
|
+
|
|
|
|
+ err = rhashtable_init(&priv->flow_table, &nfp_flower_table_params);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
|
|
get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
|
|
|
|
|
|
/* Init ring buffer and unallocated mask_ids. */
|
|
/* Init ring buffer and unallocated mask_ids. */
|
|
@@ -402,7 +433,7 @@ int nfp_flower_metadata_init(struct nfp_app *app)
|
|
kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
|
|
kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
|
|
NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
|
|
NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
|
|
if (!priv->mask_ids.mask_id_free_list.buf)
|
|
if (!priv->mask_ids.mask_id_free_list.buf)
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ goto err_free_flow_table;
|
|
|
|
|
|
priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
|
|
priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
|
|
|
|
|
|
@@ -416,18 +447,29 @@ int nfp_flower_metadata_init(struct nfp_app *app)
|
|
/* Init ring buffer and unallocated stats_ids. */
|
|
/* Init ring buffer and unallocated stats_ids. */
|
|
priv->stats_ids.free_list.buf =
|
|
priv->stats_ids.free_list.buf =
|
|
vmalloc(array_size(NFP_FL_STATS_ELEM_RS,
|
|
vmalloc(array_size(NFP_FL_STATS_ELEM_RS,
|
|
- NFP_FL_STATS_ENTRY_RS));
|
|
|
|
|
|
+ priv->stats_ring_size));
|
|
if (!priv->stats_ids.free_list.buf)
|
|
if (!priv->stats_ids.free_list.buf)
|
|
goto err_free_last_used;
|
|
goto err_free_last_used;
|
|
|
|
|
|
- priv->stats_ids.init_unalloc = NFP_FL_REPEATED_HASH_MAX;
|
|
|
|
|
|
+ priv->stats_ids.init_unalloc = host_ctx_count;
|
|
|
|
+
|
|
|
|
+ priv->stats = kvmalloc_array(priv->stats_ring_size,
|
|
|
|
+ sizeof(struct nfp_fl_stats), GFP_KERNEL);
|
|
|
|
+ if (!priv->stats)
|
|
|
|
+ goto err_free_ring_buf;
|
|
|
|
+
|
|
|
|
+ spin_lock_init(&priv->stats_lock);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+err_free_ring_buf:
|
|
|
|
+ vfree(priv->stats_ids.free_list.buf);
|
|
err_free_last_used:
|
|
err_free_last_used:
|
|
kfree(priv->mask_ids.last_used);
|
|
kfree(priv->mask_ids.last_used);
|
|
err_free_mask_id:
|
|
err_free_mask_id:
|
|
kfree(priv->mask_ids.mask_id_free_list.buf);
|
|
kfree(priv->mask_ids.mask_id_free_list.buf);
|
|
|
|
+err_free_flow_table:
|
|
|
|
+ rhashtable_destroy(&priv->flow_table);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -438,6 +480,9 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app)
|
|
if (!priv)
|
|
if (!priv)
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
+ rhashtable_free_and_destroy(&priv->flow_table,
|
|
|
|
+ nfp_check_rhashtable_empty, NULL);
|
|
|
|
+ kvfree(priv->stats);
|
|
kfree(priv->mask_ids.mask_id_free_list.buf);
|
|
kfree(priv->mask_ids.mask_id_free_list.buf);
|
|
kfree(priv->mask_ids.last_used);
|
|
kfree(priv->mask_ids.last_used);
|
|
vfree(priv->stats_ids.free_list.buf);
|
|
vfree(priv->stats_ids.free_list.buf);
|