Skip to content

Commit 3b3233f

Browse files
Raed SalemLeon Romanovsky
authored andcommitted
IB/mlx5: Add flow counters binding support
Associates a counters with a flow when IB_FLOW_SPEC_ACTION_COUNT is part of the flow specifications. The counters user space placements of location and description (index, description) pairs are passed as private data of the counters flow specification. Reviewed-by: Yishai Hadas <[email protected]> Signed-off-by: Raed Salem <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent b29e2a1 commit 3b3233f

File tree

4 files changed

+249
-13
lines changed

4 files changed

+249
-13
lines changed

drivers/infiniband/hw/mlx5/main.c

Lines changed: 209 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,7 @@ static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val)
24492449
#define LAST_TUNNEL_FIELD tunnel_id
24502450
#define LAST_FLOW_TAG_FIELD tag_id
24512451
#define LAST_DROP_FIELD size
2452+
#define LAST_COUNTERS_FIELD counters
24522453

24532454
/* Field is the last supported field */
24542455
#define FIELDS_NOT_SUPPORTED(filter, field)\
@@ -2721,6 +2722,18 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
27212722
if (ret)
27222723
return ret;
27232724
break;
2725+
case IB_FLOW_SPEC_ACTION_COUNT:
2726+
if (FIELDS_NOT_SUPPORTED(ib_spec->flow_count,
2727+
LAST_COUNTERS_FIELD))
2728+
return -EOPNOTSUPP;
2729+
2730+
/* for now support only one counters spec per flow */
2731+
if (action->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
2732+
return -EINVAL;
2733+
2734+
action->counters = ib_spec->flow_count.counters;
2735+
action->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
2736+
break;
27242737
default:
27252738
return -EINVAL;
27262739
}
@@ -2868,6 +2881,17 @@ static void put_flow_table(struct mlx5_ib_dev *dev,
28682881
}
28692882
}
28702883

2884+
static void counters_clear_description(struct ib_counters *counters)
2885+
{
2886+
struct mlx5_ib_mcounters *mcounters = to_mcounters(counters);
2887+
2888+
mutex_lock(&mcounters->mcntrs_mutex);
2889+
kfree(mcounters->counters_data);
2890+
mcounters->counters_data = NULL;
2891+
mcounters->cntrs_max_index = 0;
2892+
mutex_unlock(&mcounters->mcntrs_mutex);
2893+
}
2894+
28712895
static int mlx5_ib_destroy_flow(struct ib_flow *flow_id)
28722896
{
28732897
struct mlx5_ib_dev *dev = to_mdev(flow_id->qp->device);
@@ -2887,8 +2911,11 @@ static int mlx5_ib_destroy_flow(struct ib_flow *flow_id)
28872911

28882912
mlx5_del_flow_rules(handler->rule);
28892913
put_flow_table(dev, handler->prio, true);
2890-
mutex_unlock(&dev->flow_db->lock);
2914+
if (handler->ibcounters &&
2915+
atomic_read(&handler->ibcounters->usecnt) == 1)
2916+
counters_clear_description(handler->ibcounters);
28912917

2918+
mutex_unlock(&dev->flow_db->lock);
28922919
kfree(handler);
28932920

28942921
return 0;
@@ -3008,21 +3035,127 @@ static void set_underlay_qp(struct mlx5_ib_dev *dev,
30083035
}
30093036
}
30103037

3038+
static int counters_set_description(struct ib_counters *counters,
3039+
enum mlx5_ib_counters_type counters_type,
3040+
struct mlx5_ib_flow_counters_desc *desc_data,
3041+
u32 ncounters)
3042+
{
3043+
struct mlx5_ib_mcounters *mcounters = to_mcounters(counters);
3044+
u32 cntrs_max_index = 0;
3045+
int i;
3046+
3047+
if (counters_type != MLX5_IB_COUNTERS_FLOW)
3048+
return -EINVAL;
3049+
3050+
/* init the fields for the object */
3051+
mcounters->type = counters_type;
3052+
mcounters->ncounters = ncounters;
3053+
/* each counter entry have both description and index pair */
3054+
for (i = 0; i < ncounters; i++) {
3055+
if (desc_data[i].description > IB_COUNTER_BYTES)
3056+
return -EINVAL;
3057+
3058+
if (cntrs_max_index <= desc_data[i].index)
3059+
cntrs_max_index = desc_data[i].index + 1;
3060+
}
3061+
3062+
mutex_lock(&mcounters->mcntrs_mutex);
3063+
mcounters->counters_data = desc_data;
3064+
mcounters->cntrs_max_index = cntrs_max_index;
3065+
mutex_unlock(&mcounters->mcntrs_mutex);
3066+
3067+
return 0;
3068+
}
3069+
3070+
#define MAX_COUNTERS_NUM (USHRT_MAX / (sizeof(u32) * 2))
3071+
static int flow_counters_set_data(struct ib_counters *ibcounters,
3072+
struct mlx5_ib_create_flow *ucmd)
3073+
{
3074+
struct mlx5_ib_mcounters *mcounters = to_mcounters(ibcounters);
3075+
struct mlx5_ib_flow_counters_data *cntrs_data = NULL;
3076+
struct mlx5_ib_flow_counters_desc *desc_data = NULL;
3077+
bool hw_hndl = false;
3078+
int ret = 0;
3079+
3080+
if (ucmd && ucmd->ncounters_data != 0) {
3081+
cntrs_data = ucmd->data;
3082+
if (cntrs_data->ncounters > MAX_COUNTERS_NUM)
3083+
return -EINVAL;
3084+
3085+
desc_data = kcalloc(cntrs_data->ncounters,
3086+
sizeof(*desc_data),
3087+
GFP_KERNEL);
3088+
if (!desc_data)
3089+
return -ENOMEM;
3090+
3091+
if (copy_from_user(desc_data,
3092+
u64_to_user_ptr(cntrs_data->counters_data),
3093+
sizeof(*desc_data) * cntrs_data->ncounters)) {
3094+
ret = -EFAULT;
3095+
goto free;
3096+
}
3097+
}
3098+
3099+
if (!mcounters->hw_cntrs_hndl) {
3100+
mcounters->hw_cntrs_hndl = mlx5_fc_create(
3101+
to_mdev(ibcounters->device)->mdev, false);
3102+
if (!mcounters->hw_cntrs_hndl) {
3103+
ret = -ENOMEM;
3104+
goto free;
3105+
}
3106+
hw_hndl = true;
3107+
}
3108+
3109+
if (desc_data) {
3110+
/* counters already bound to at least one flow */
3111+
if (mcounters->cntrs_max_index) {
3112+
ret = -EINVAL;
3113+
goto free_hndl;
3114+
}
3115+
3116+
ret = counters_set_description(ibcounters,
3117+
MLX5_IB_COUNTERS_FLOW,
3118+
desc_data,
3119+
cntrs_data->ncounters);
3120+
if (ret)
3121+
goto free_hndl;
3122+
3123+
} else if (!mcounters->cntrs_max_index) {
3124+
/* counters not bound yet, must have udata passed */
3125+
ret = -EINVAL;
3126+
goto free_hndl;
3127+
}
3128+
3129+
return 0;
3130+
3131+
free_hndl:
3132+
if (hw_hndl) {
3133+
mlx5_fc_destroy(to_mdev(ibcounters->device)->mdev,
3134+
mcounters->hw_cntrs_hndl);
3135+
mcounters->hw_cntrs_hndl = NULL;
3136+
}
3137+
free:
3138+
kfree(desc_data);
3139+
return ret;
3140+
}
3141+
30113142
static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
30123143
struct mlx5_ib_flow_prio *ft_prio,
30133144
const struct ib_flow_attr *flow_attr,
30143145
struct mlx5_flow_destination *dst,
3015-
u32 underlay_qpn)
3146+
u32 underlay_qpn,
3147+
struct mlx5_ib_create_flow *ucmd)
30163148
{
30173149
struct mlx5_flow_table *ft = ft_prio->flow_table;
30183150
struct mlx5_ib_flow_handler *handler;
30193151
struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
30203152
struct mlx5_flow_spec *spec;
3021-
struct mlx5_flow_destination *rule_dst = dst;
3153+
struct mlx5_flow_destination dest_arr[2] = {};
3154+
struct mlx5_flow_destination *rule_dst = dest_arr;
30223155
const void *ib_flow = (const void *)flow_attr + sizeof(*flow_attr);
30233156
unsigned int spec_index;
30243157
int err = 0;
3025-
int dest_num = 1;
3158+
int dest_num = 0;
30263159
bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
30273160

30283161
if (!is_valid_attr(dev->mdev, flow_attr))
@@ -3036,6 +3169,10 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
30363169
}
30373170

30383171
INIT_LIST_HEAD(&handler->list);
3172+
if (dst) {
3173+
memcpy(&dest_arr[0], dst, sizeof(*dst));
3174+
dest_num++;
3175+
}
30393176

30403177
for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
30413178
err = parse_flow_attr(dev->mdev, spec->match_criteria,
@@ -3070,15 +3207,30 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
30703207
goto free;
30713208
}
30723209

3210+
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
3211+
err = flow_counters_set_data(flow_act.counters, ucmd);
3212+
if (err)
3213+
goto free;
3214+
3215+
handler->ibcounters = flow_act.counters;
3216+
dest_arr[dest_num].type =
3217+
MLX5_FLOW_DESTINATION_TYPE_COUNTER;
3218+
dest_arr[dest_num].counter =
3219+
to_mcounters(flow_act.counters)->hw_cntrs_hndl;
3220+
dest_num++;
3221+
}
3222+
30733223
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
3074-
rule_dst = NULL;
3075-
dest_num = 0;
3224+
if (!(flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT)) {
3225+
rule_dst = NULL;
3226+
dest_num = 0;
3227+
}
30763228
} else {
30773229
if (is_egress)
30783230
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
30793231
else
30803232
flow_act.action |=
3081-
dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
3233+
dest_num ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
30823234
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
30833235
}
30843236

@@ -3104,8 +3256,12 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
31043256

31053257
ft_prio->flow_table = ft;
31063258
free:
3107-
if (err)
3259+
if (err && handler) {
3260+
if (handler->ibcounters &&
3261+
atomic_read(&handler->ibcounters->usecnt) == 1)
3262+
counters_clear_description(handler->ibcounters);
31083263
kfree(handler);
3264+
}
31093265
kvfree(spec);
31103266
return err ? ERR_PTR(err) : handler;
31113267
}
@@ -3115,7 +3271,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
31153271
const struct ib_flow_attr *flow_attr,
31163272
struct mlx5_flow_destination *dst)
31173273
{
3118-
return _create_flow_rule(dev, ft_prio, flow_attr, dst, 0);
3274+
return _create_flow_rule(dev, ft_prio, flow_attr, dst, 0, NULL);
31193275
}
31203276

31213277
static struct mlx5_ib_flow_handler *create_dont_trap_rule(struct mlx5_ib_dev *dev,
@@ -3255,12 +3411,43 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
32553411
struct mlx5_ib_flow_prio *ft_prio_tx = NULL;
32563412
struct mlx5_ib_flow_prio *ft_prio;
32573413
bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
3414+
struct mlx5_ib_create_flow *ucmd = NULL, ucmd_hdr;
3415+
size_t min_ucmd_sz, required_ucmd_sz;
32583416
int err;
32593417
int underlay_qpn;
32603418

3261-
if (udata &&
3262-
udata->inlen && !ib_is_udata_cleared(udata, 0, udata->inlen))
3263-
return ERR_PTR(-EOPNOTSUPP);
3419+
if (udata && udata->inlen) {
3420+
min_ucmd_sz = offsetof(typeof(ucmd_hdr), reserved) +
3421+
sizeof(ucmd_hdr.reserved);
3422+
if (udata->inlen < min_ucmd_sz)
3423+
return ERR_PTR(-EOPNOTSUPP);
3424+
3425+
err = ib_copy_from_udata(&ucmd_hdr, udata, min_ucmd_sz);
3426+
if (err)
3427+
return ERR_PTR(err);
3428+
3429+
/* currently supports only one counters data */
3430+
if (ucmd_hdr.ncounters_data > 1)
3431+
return ERR_PTR(-EINVAL);
3432+
3433+
required_ucmd_sz = min_ucmd_sz +
3434+
sizeof(struct mlx5_ib_flow_counters_data) *
3435+
ucmd_hdr.ncounters_data;
3436+
if (udata->inlen > required_ucmd_sz &&
3437+
!ib_is_udata_cleared(udata, required_ucmd_sz,
3438+
udata->inlen - required_ucmd_sz))
3439+
return ERR_PTR(-EOPNOTSUPP);
3440+
3441+
ucmd = kzalloc(required_ucmd_sz, GFP_KERNEL);
3442+
if (!ucmd)
3443+
return ERR_PTR(-ENOMEM);
3444+
3445+
err = ib_copy_from_udata(ucmd, udata, required_ucmd_sz);
3446+
if (err) {
3447+
kfree(ucmd);
3448+
return ERR_PTR(err);
3449+
}
3450+
}
32643451

32653452
if (flow_attr->priority > MLX5_IB_FLOW_LAST_PRIO)
32663453
return ERR_PTR(-ENOMEM);
@@ -3315,7 +3502,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
33153502
underlay_qpn = (mqp->flags & MLX5_IB_QP_UNDERLAY) ?
33163503
mqp->underlay_qpn : 0;
33173504
handler = _create_flow_rule(dev, ft_prio, flow_attr,
3318-
dst, underlay_qpn);
3505+
dst, underlay_qpn, ucmd);
33193506
}
33203507
} else if (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
33213508
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT) {
@@ -3336,6 +3523,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
33363523

33373524
mutex_unlock(&dev->flow_db->lock);
33383525
kfree(dst);
3526+
kfree(ucmd);
33393527

33403528
return &handler->ibflow;
33413529

@@ -3346,6 +3534,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
33463534
unlock:
33473535
mutex_unlock(&dev->flow_db->lock);
33483536
kfree(dst);
3537+
kfree(ucmd);
33493538
kfree(handler);
33503539
return ERR_PTR(err);
33513540
}
@@ -5010,6 +5199,11 @@ static int mlx5_ib_destroy_counters(struct ib_counters *counters)
50105199
{
50115200
struct mlx5_ib_mcounters *mcounters = to_mcounters(counters);
50125201

5202+
counters_clear_description(counters);
5203+
if (mcounters->hw_cntrs_hndl)
5204+
mlx5_fc_destroy(to_mdev(counters->device)->mdev,
5205+
mcounters->hw_cntrs_hndl);
5206+
50135207
kfree(mcounters);
50145208

50155209
return 0;
@@ -5024,6 +5218,8 @@ static struct ib_counters *mlx5_ib_create_counters(struct ib_device *device,
50245218
if (!mcounters)
50255219
return ERR_PTR(-ENOMEM);
50265220

5221+
mutex_init(&mcounters->mcntrs_mutex);
5222+
50275223
return &mcounters->ibcntrs;
50285224
}
50295225

drivers/infiniband/hw/mlx5/mlx5_ib.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ struct mlx5_ib_flow_handler {
175175
struct ib_flow ibflow;
176176
struct mlx5_ib_flow_prio *prio;
177177
struct mlx5_flow_handle *rule;
178+
struct ib_counters *ibcounters;
178179
};
179180

180181
struct mlx5_ib_flow_db {
@@ -813,8 +814,22 @@ struct mlx5_memic {
813814
DECLARE_BITMAP(memic_alloc_pages, MLX5_MAX_MEMIC_PAGES);
814815
};
815816

817+
enum mlx5_ib_counters_type {
818+
MLX5_IB_COUNTERS_FLOW,
819+
};
820+
816821
struct mlx5_ib_mcounters {
817822
struct ib_counters ibcntrs;
823+
enum mlx5_ib_counters_type type;
824+
void *hw_cntrs_hndl;
825+
/* max index set as part of create_flow */
826+
u32 cntrs_max_index;
827+
/* number of counters data entries (<description,index> pair) */
828+
u32 ncounters;
829+
/* counters data array for descriptions and indexes */
830+
struct mlx5_ib_flow_counters_desc *counters_data;
831+
/* protects access to mcounters internal data */
832+
struct mutex mcntrs_mutex;
818833
};
819834

820835
static inline struct mlx5_ib_mcounters *

include/linux/mlx5/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ struct mlx5_flow_act {
160160
u32 modify_id;
161161
uintptr_t esp_id;
162162
struct mlx5_fs_vlan vlan;
163+
struct ib_counters *counters;
163164
};
164165

165166
#define MLX5_DECLARE_FLOW_ACT(name) \

0 commit comments

Comments
 (0)