Skip to content

Commit d13674b

Browse files
ozshlomoPaolo Abeni
authored andcommitted
net/mlx5e: TC, map tc action cookie to a hw counter
Currently a hardware counter is associated with a flow cookie. This does not apply to flows using branching action which are required to return per action stats. A single counter may apply to multiple actions. Scan the flow actions in reverse (from the last to the first action) while caching the last counter. Associate all the flow attribute tc action cookies with the current cached counter. Signed-off-by: Oz Shlomo <ozsh@nvidia.com> Reviewed-by: Roi Dayan <roid@nvidia.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent cca7eac commit d13674b

File tree

5 files changed

+224
-1
lines changed

5 files changed

+224
-1
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en_tc.o en/rep/tc.o en/rep/neigh.o \
4747
en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
4848
en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
4949
en/tc/post_act.o en/tc/int_port.o en/tc/meter.o \
50-
en/tc/post_meter.o
50+
en/tc/post_meter.o en/tc/act_stats.o
5151

5252
mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
5353
en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
4+
#include <linux/rhashtable.h>
5+
#include <net/flow_offload.h>
6+
#include "en/tc_priv.h"
7+
#include "act_stats.h"
8+
#include "en/fs.h"
9+
10+
struct mlx5e_tc_act_stats_handle {
11+
struct rhashtable ht;
12+
spinlock_t ht_lock; /* protects hashtable */
13+
};
14+
15+
struct mlx5e_tc_act_stats {
16+
unsigned long tc_act_cookie;
17+
18+
struct mlx5_fc *counter;
19+
u64 lastpackets;
20+
u64 lastbytes;
21+
22+
struct rhash_head hash;
23+
struct rcu_head rcu_head;
24+
};
25+
26+
static const struct rhashtable_params act_counters_ht_params = {
27+
.head_offset = offsetof(struct mlx5e_tc_act_stats, hash),
28+
.key_offset = 0,
29+
.key_len = offsetof(struct mlx5e_tc_act_stats, counter),
30+
.automatic_shrinking = true,
31+
};
32+
33+
struct mlx5e_tc_act_stats_handle *
34+
mlx5e_tc_act_stats_create(void)
35+
{
36+
struct mlx5e_tc_act_stats_handle *handle;
37+
int err;
38+
39+
handle = kvzalloc(sizeof(*handle), GFP_KERNEL);
40+
if (IS_ERR(handle))
41+
return ERR_PTR(-ENOMEM);
42+
43+
err = rhashtable_init(&handle->ht, &act_counters_ht_params);
44+
if (err)
45+
goto err;
46+
47+
spin_lock_init(&handle->ht_lock);
48+
return handle;
49+
err:
50+
kvfree(handle);
51+
return ERR_PTR(err);
52+
}
53+
54+
void mlx5e_tc_act_stats_free(struct mlx5e_tc_act_stats_handle *handle)
55+
{
56+
rhashtable_destroy(&handle->ht);
57+
kvfree(handle);
58+
}
59+
60+
static int
61+
mlx5e_tc_act_stats_add(struct mlx5e_tc_act_stats_handle *handle,
62+
unsigned long act_cookie,
63+
struct mlx5_fc *counter)
64+
{
65+
struct mlx5e_tc_act_stats *act_stats, *old_act_stats;
66+
struct rhashtable *ht = &handle->ht;
67+
int err = 0;
68+
69+
act_stats = kvzalloc(sizeof(*act_stats), GFP_KERNEL);
70+
if (!act_stats)
71+
return -ENOMEM;
72+
73+
act_stats->tc_act_cookie = act_cookie;
74+
act_stats->counter = counter;
75+
76+
rcu_read_lock();
77+
old_act_stats = rhashtable_lookup_get_insert_fast(ht,
78+
&act_stats->hash,
79+
act_counters_ht_params);
80+
if (IS_ERR(old_act_stats)) {
81+
err = PTR_ERR(old_act_stats);
82+
goto err_hash_insert;
83+
} else if (old_act_stats) {
84+
err = -EEXIST;
85+
goto err_hash_insert;
86+
}
87+
rcu_read_unlock();
88+
89+
return 0;
90+
91+
err_hash_insert:
92+
rcu_read_unlock();
93+
kvfree(act_stats);
94+
return err;
95+
}
96+
97+
void
98+
mlx5e_tc_act_stats_del_flow(struct mlx5e_tc_act_stats_handle *handle,
99+
struct mlx5e_tc_flow *flow)
100+
{
101+
struct mlx5_flow_attr *attr;
102+
struct mlx5e_tc_act_stats *act_stats;
103+
int i;
104+
105+
list_for_each_entry(attr, &flow->attrs, list) {
106+
for (i = 0; i < attr->tc_act_cookies_count; i++) {
107+
struct rhashtable *ht = &handle->ht;
108+
109+
spin_lock(&handle->ht_lock);
110+
act_stats = rhashtable_lookup_fast(ht,
111+
&attr->tc_act_cookies[i],
112+
act_counters_ht_params);
113+
if (act_stats &&
114+
rhashtable_remove_fast(ht, &act_stats->hash,
115+
act_counters_ht_params) == 0)
116+
kvfree_rcu(act_stats, rcu_head);
117+
118+
spin_unlock(&handle->ht_lock);
119+
}
120+
}
121+
}
122+
123+
int
124+
mlx5e_tc_act_stats_add_flow(struct mlx5e_tc_act_stats_handle *handle,
125+
struct mlx5e_tc_flow *flow)
126+
{
127+
struct mlx5_fc *curr_counter = NULL;
128+
unsigned long last_cookie = 0;
129+
struct mlx5_flow_attr *attr;
130+
int err;
131+
int i;
132+
133+
list_for_each_entry(attr, &flow->attrs, list) {
134+
if (attr->counter)
135+
curr_counter = attr->counter;
136+
137+
for (i = 0; i < attr->tc_act_cookies_count; i++) {
138+
/* jump over identical ids (e.g. pedit)*/
139+
if (last_cookie == attr->tc_act_cookies[i])
140+
continue;
141+
142+
err = mlx5e_tc_act_stats_add(handle, attr->tc_act_cookies[i], curr_counter);
143+
if (err)
144+
goto out_err;
145+
last_cookie = attr->tc_act_cookies[i];
146+
}
147+
}
148+
149+
return 0;
150+
out_err:
151+
mlx5e_tc_act_stats_del_flow(handle, flow);
152+
return err;
153+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3+
4+
#ifndef __MLX5_EN_ACT_STATS_H__
5+
#define __MLX5_EN_ACT_STATS_H__
6+
7+
#include <net/flow_offload.h>
8+
#include "en/tc_priv.h"
9+
10+
struct mlx5e_tc_act_stats_handle;
11+
12+
struct mlx5e_tc_act_stats_handle *mlx5e_tc_act_stats_create(void);
13+
void mlx5e_tc_act_stats_free(struct mlx5e_tc_act_stats_handle *handle);
14+
15+
int
16+
mlx5e_tc_act_stats_add_flow(struct mlx5e_tc_act_stats_handle *handle,
17+
struct mlx5e_tc_flow *flow);
18+
19+
void
20+
mlx5e_tc_act_stats_del_flow(struct mlx5e_tc_act_stats_handle *handle,
21+
struct mlx5e_tc_flow *flow);
22+
23+
#endif /* __MLX5_EN_ACT_STATS_H__ */

drivers/net/ethernet/mellanox/mlx5/core/en_rep.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ struct mlx5_rep_uplink_priv {
100100
struct mlx5e_tc_int_port_priv *int_port_priv;
101101

102102
struct mlx5e_flow_meters *flow_meters;
103+
104+
/* tc action stats */
105+
struct mlx5e_tc_act_stats_handle *action_stats_handle;
103106
};
104107

105108
struct mlx5e_rep_priv {

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <net/bonding.h>
4646
#include "en.h"
4747
#include "en/tc/post_act.h"
48+
#include "en/tc/act_stats.h"
4849
#include "en_rep.h"
4950
#include "en/rep/tc.h"
5051
#include "en/rep/neigh.h"
@@ -101,6 +102,9 @@ struct mlx5e_tc_table {
101102
struct mapping_ctx *mapping;
102103
struct mlx5e_hairpin_params hairpin_params;
103104
struct dentry *dfs_root;
105+
106+
/* tc action stats */
107+
struct mlx5e_tc_act_stats_handle *action_stats_handle;
104108
};
105109

106110
struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
@@ -286,6 +290,24 @@ mlx5e_tc_match_to_reg_set_and_get_id(struct mlx5_core_dev *mdev,
286290
return err;
287291
}
288292

293+
static struct mlx5e_tc_act_stats_handle *
294+
get_act_stats_handle(struct mlx5e_priv *priv)
295+
{
296+
struct mlx5e_tc_table *tc = mlx5e_fs_get_tc(priv->fs);
297+
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
298+
struct mlx5_rep_uplink_priv *uplink_priv;
299+
struct mlx5e_rep_priv *uplink_rpriv;
300+
301+
if (is_mdev_switchdev_mode(priv->mdev)) {
302+
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
303+
uplink_priv = &uplink_rpriv->uplink_priv;
304+
305+
return uplink_priv->action_stats_handle;
306+
}
307+
308+
return tc->action_stats_handle;
309+
}
310+
289311
struct mlx5e_tc_int_port_priv *
290312
mlx5e_get_int_port_priv(struct mlx5e_priv *priv)
291313
{
@@ -2026,6 +2048,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
20262048
if (err)
20272049
goto err_out;
20282050

2051+
err = mlx5e_tc_act_stats_add_flow(get_act_stats_handle(priv), flow);
2052+
if (err)
2053+
goto err_out;
2054+
20292055
/* we get here if one of the following takes place:
20302056
* (1) there's no error
20312057
* (2) there's an encap action and we don't have valid neigh
@@ -2120,6 +2146,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
21202146
if (flow_flag_test(flow, L3_TO_L2_DECAP))
21212147
mlx5e_detach_decap(priv, flow);
21222148

2149+
mlx5e_tc_act_stats_del_flow(get_act_stats_handle(priv), flow);
2150+
21232151
free_flow_post_acts(flow);
21242152
free_branch_attr(flow, attr->branch_true);
21252153
free_branch_attr(flow, attr->branch_false);
@@ -5331,8 +5359,16 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
53315359

53325360
mlx5e_tc_debugfs_init(tc, mlx5e_fs_get_debugfs_root(priv->fs));
53335361

5362+
tc->action_stats_handle = mlx5e_tc_act_stats_create();
5363+
if (IS_ERR(tc->action_stats_handle))
5364+
goto err_act_stats;
5365+
53345366
return 0;
53355367

5368+
err_act_stats:
5369+
unregister_netdevice_notifier_dev_net(priv->netdev,
5370+
&tc->netdevice_nb,
5371+
&tc->netdevice_nn);
53365372
err_reg:
53375373
mlx5_tc_ct_clean(tc->ct);
53385374
mlx5e_tc_post_act_destroy(tc->post_act);
@@ -5382,6 +5418,7 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv)
53825418
mapping_destroy(tc->mapping);
53835419
mlx5_chains_destroy(tc->chains);
53845420
mlx5e_tc_nic_destroy_miss_table(priv);
5421+
mlx5e_tc_act_stats_free(tc->action_stats_handle);
53855422
}
53865423

53875424
int mlx5e_tc_ht_init(struct rhashtable *tc_ht)
@@ -5458,8 +5495,14 @@ int mlx5e_tc_esw_init(struct mlx5_rep_uplink_priv *uplink_priv)
54585495
goto err_register_fib_notifier;
54595496
}
54605497

5498+
uplink_priv->action_stats_handle = mlx5e_tc_act_stats_create();
5499+
if (IS_ERR(uplink_priv->action_stats_handle))
5500+
goto err_action_counter;
5501+
54615502
return 0;
54625503

5504+
err_action_counter:
5505+
mlx5e_tc_tun_cleanup(uplink_priv->encap);
54635506
err_register_fib_notifier:
54645507
mapping_destroy(uplink_priv->tunnel_enc_opts_mapping);
54655508
err_enc_opts_mapping:
@@ -5486,6 +5529,7 @@ void mlx5e_tc_esw_cleanup(struct mlx5_rep_uplink_priv *uplink_priv)
54865529
mlx5_tc_ct_clean(uplink_priv->ct_priv);
54875530
mlx5e_flow_meters_cleanup(uplink_priv->flow_meters);
54885531
mlx5e_tc_post_act_destroy(uplink_priv->post_act);
5532+
mlx5e_tc_act_stats_free(uplink_priv->action_stats_handle);
54895533
}
54905534

54915535
int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags)

0 commit comments

Comments
 (0)