Skip to content

Commit 0f45e69

Browse files
committed
Merge tag 'verbs_flow_counters' of git://git.kernel.org/pub/scm/linux/kernel/git/leon/linux-rdma.git into for-next
Pull verbs counters series from Leon Romanovsky: ==================== Verbs flow counters support This series comes to allow user space applications to monitor real time traffic activity and events of the verbs objects it manages, e.g.: ibv_qp, ibv_wq, ibv_flow. The API enables generic counters creation and define mapping to association with a verbs object, the current mlx5 driver is using this API for flow counters. With this API, an application can monitor the entire life cycle of object activity, defined here as a static counters attachment. This API also allows dynamic counters monitoring of measurement points for a partial period in the verbs object life cycle. In addition it presents the implementation of the generic counters interface. This will be achieved by extending flow creation by adding a new flow count specification type which allows the user to associate a previously created flow counters using the generic verbs counters interface to the created flow, once associated the user could read statistics by using the read function of the generic counters interface. The API includes: 1. create and destroyed API of a new counters objects 2. read the counters values from HW Note: Attaching API to allow application to define the measurement points per objects is a user space only API and this data is passed to kernel when the counted object (e.g. flow) is created with the counters object. =================== * tag 'verbs_flow_counters': IB/mlx5: Add counters read support IB/mlx5: Add flow counters read support IB/mlx5: Add flow counters binding support IB/mlx5: Add counters create and destroy support IB/uverbs: Add support for flow counters IB/core: Add support for flow counters IB/core: Support passing uhw for create_flow IB/uverbs: Add read counters support IB/core: Introduce counters read verb IB/uverbs: Add create/destroy counters support IB/core: Introduce counters object and its create/destroy IB/uverbs: Add an ib_uobject getter to ioctl() infrastructure net/mlx5: Export flow counter related API net/mlx5: Use flow counter pointer as input to the query function
2 parents 27d036e + 1a1e03d commit 0f45e69

File tree

20 files changed

+712
-56
lines changed

20 files changed

+712
-56
lines changed

drivers/infiniband/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
3737
rdma_core.o uverbs_std_types.o uverbs_ioctl.o \
3838
uverbs_ioctl_merge.o uverbs_std_types_cq.o \
3939
uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
40-
uverbs_std_types_mr.o
40+
uverbs_std_types_mr.o uverbs_std_types_counters.o

drivers/infiniband/core/uverbs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ struct ib_uverbs_flow_spec {
263263
struct ib_uverbs_flow_spec_action_tag flow_tag;
264264
struct ib_uverbs_flow_spec_action_drop drop;
265265
struct ib_uverbs_flow_spec_action_handle action;
266+
struct ib_uverbs_flow_spec_action_count flow_count;
266267
};
267268
};
268269

@@ -287,6 +288,7 @@ extern const struct uverbs_object_def UVERBS_OBJECT(UVERBS_OBJECT_RWQ_IND_TBL);
287288
extern const struct uverbs_object_def UVERBS_OBJECT(UVERBS_OBJECT_XRCD);
288289
extern const struct uverbs_object_def UVERBS_OBJECT(UVERBS_OBJECT_FLOW_ACTION);
289290
extern const struct uverbs_object_def UVERBS_OBJECT(UVERBS_OBJECT_DM);
291+
extern const struct uverbs_object_def UVERBS_OBJECT(UVERBS_OBJECT_COUNTERS);
290292

291293
#define IB_UVERBS_DECLARE_CMD(name) \
292294
ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \

drivers/infiniband/core/uverbs_cmd.c

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,43 +2748,82 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
27482748
struct ib_uflow_resources {
27492749
size_t max;
27502750
size_t num;
2751-
struct ib_flow_action *collection[0];
2751+
size_t collection_num;
2752+
size_t counters_num;
2753+
struct ib_counters **counters;
2754+
struct ib_flow_action **collection;
27522755
};
27532756

27542757
static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
27552758
{
27562759
struct ib_uflow_resources *resources;
27572760

2758-
resources =
2759-
kmalloc(sizeof(*resources) +
2760-
num_specs * sizeof(*resources->collection), GFP_KERNEL);
2761+
resources = kzalloc(sizeof(*resources), GFP_KERNEL);
27612762

27622763
if (!resources)
2763-
return NULL;
2764+
goto err_res;
2765+
2766+
resources->counters =
2767+
kcalloc(num_specs, sizeof(*resources->counters), GFP_KERNEL);
2768+
2769+
if (!resources->counters)
2770+
goto err_cnt;
2771+
2772+
resources->collection =
2773+
kcalloc(num_specs, sizeof(*resources->collection), GFP_KERNEL);
2774+
2775+
if (!resources->collection)
2776+
goto err_collection;
27642777

2765-
resources->num = 0;
27662778
resources->max = num_specs;
27672779

27682780
return resources;
2781+
2782+
err_collection:
2783+
kfree(resources->counters);
2784+
err_cnt:
2785+
kfree(resources);
2786+
err_res:
2787+
return NULL;
27692788
}
27702789

27712790
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
27722791
{
27732792
unsigned int i;
27742793

2775-
for (i = 0; i < uflow_res->num; i++)
2794+
for (i = 0; i < uflow_res->collection_num; i++)
27762795
atomic_dec(&uflow_res->collection[i]->usecnt);
27772796

2797+
for (i = 0; i < uflow_res->counters_num; i++)
2798+
atomic_dec(&uflow_res->counters[i]->usecnt);
2799+
2800+
kfree(uflow_res->collection);
2801+
kfree(uflow_res->counters);
27782802
kfree(uflow_res);
27792803
}
27802804

27812805
static void flow_resources_add(struct ib_uflow_resources *uflow_res,
2782-
struct ib_flow_action *action)
2806+
enum ib_flow_spec_type type,
2807+
void *ibobj)
27832808
{
27842809
WARN_ON(uflow_res->num >= uflow_res->max);
27852810

2786-
atomic_inc(&action->usecnt);
2787-
uflow_res->collection[uflow_res->num++] = action;
2811+
switch (type) {
2812+
case IB_FLOW_SPEC_ACTION_HANDLE:
2813+
atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
2814+
uflow_res->collection[uflow_res->collection_num++] =
2815+
(struct ib_flow_action *)ibobj;
2816+
break;
2817+
case IB_FLOW_SPEC_ACTION_COUNT:
2818+
atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
2819+
uflow_res->counters[uflow_res->counters_num++] =
2820+
(struct ib_counters *)ibobj;
2821+
break;
2822+
default:
2823+
WARN_ON(1);
2824+
}
2825+
2826+
uflow_res->num++;
27882827
}
27892828

27902829
static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext,
@@ -2821,9 +2860,29 @@ static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext,
28212860
return -EINVAL;
28222861
ib_spec->action.size =
28232862
sizeof(struct ib_flow_spec_action_handle);
2824-
flow_resources_add(uflow_res, ib_spec->action.act);
2863+
flow_resources_add(uflow_res,
2864+
IB_FLOW_SPEC_ACTION_HANDLE,
2865+
ib_spec->action.act);
28252866
uobj_put_obj_read(ib_spec->action.act);
28262867
break;
2868+
case IB_FLOW_SPEC_ACTION_COUNT:
2869+
if (kern_spec->flow_count.size !=
2870+
sizeof(struct ib_uverbs_flow_spec_action_count))
2871+
return -EINVAL;
2872+
ib_spec->flow_count.counters =
2873+
uobj_get_obj_read(counters,
2874+
UVERBS_OBJECT_COUNTERS,
2875+
kern_spec->flow_count.handle,
2876+
ucontext);
2877+
if (!ib_spec->flow_count.counters)
2878+
return -EINVAL;
2879+
ib_spec->flow_count.size =
2880+
sizeof(struct ib_flow_spec_action_count);
2881+
flow_resources_add(uflow_res,
2882+
IB_FLOW_SPEC_ACTION_COUNT,
2883+
ib_spec->flow_count.counters);
2884+
uobj_put_obj_read(ib_spec->flow_count.counters);
2885+
break;
28272886
default:
28282887
return -EINVAL;
28292888
}
@@ -3542,11 +3601,16 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
35423601
err = -EINVAL;
35433602
goto err_free;
35443603
}
3545-
flow_id = ib_create_flow(qp, flow_attr, IB_FLOW_DOMAIN_USER);
3604+
3605+
flow_id = qp->device->create_flow(qp, flow_attr,
3606+
IB_FLOW_DOMAIN_USER, uhw);
3607+
35463608
if (IS_ERR(flow_id)) {
35473609
err = PTR_ERR(flow_id);
35483610
goto err_free;
35493611
}
3612+
atomic_inc(&qp->usecnt);
3613+
flow_id->qp = qp;
35503614
flow_id->uobject = uobj;
35513615
uobj->object = flow_id;
35523616
uflow = container_of(uobj, typeof(*uflow), uobject);

drivers/infiniband/core/uverbs_std_types.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,8 @@ static DECLARE_UVERBS_OBJECT_TREE(uverbs_default_objects,
302302
&UVERBS_OBJECT(UVERBS_OBJECT_RWQ_IND_TBL),
303303
&UVERBS_OBJECT(UVERBS_OBJECT_XRCD),
304304
&UVERBS_OBJECT(UVERBS_OBJECT_FLOW_ACTION),
305-
&UVERBS_OBJECT(UVERBS_OBJECT_DM));
305+
&UVERBS_OBJECT(UVERBS_OBJECT_DM),
306+
&UVERBS_OBJECT(UVERBS_OBJECT_COUNTERS));
306307

307308
const struct uverbs_object_tree_def *uverbs_default_get_objects(void)
308309
{
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+
/*
3+
* Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
4+
*
5+
* This software is available to you under a choice of one of two
6+
* licenses. You may choose to be licensed under the terms of the GNU
7+
* General Public License (GPL) Version 2, available from the file
8+
* COPYING in the main directory of this source tree, or the
9+
* OpenIB.org BSD license below:
10+
*
11+
* Redistribution and use in source and binary forms, with or
12+
* without modification, are permitted provided that the following
13+
* conditions are met:
14+
*
15+
* - Redistributions of source code must retain the above
16+
* copyright notice, this list of conditions and the following
17+
* disclaimer.
18+
*
19+
* - Redistributions in binary form must reproduce the above
20+
* copyright notice, this list of conditions and the following
21+
* disclaimer in the documentation and/or other materials
22+
* provided with the distribution.
23+
*
24+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31+
* SOFTWARE.
32+
*/
33+
34+
#include "uverbs.h"
35+
#include <rdma/uverbs_std_types.h>
36+
37+
static int uverbs_free_counters(struct ib_uobject *uobject,
38+
enum rdma_remove_reason why)
39+
{
40+
struct ib_counters *counters = uobject->object;
41+
42+
if (why == RDMA_REMOVE_DESTROY &&
43+
atomic_read(&counters->usecnt))
44+
return -EBUSY;
45+
46+
return counters->device->destroy_counters(counters);
47+
}
48+
49+
static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_CREATE)(struct ib_device *ib_dev,
50+
struct ib_uverbs_file *file,
51+
struct uverbs_attr_bundle *attrs)
52+
{
53+
struct ib_counters *counters;
54+
struct ib_uobject *uobj;
55+
int ret;
56+
57+
/*
58+
* This check should be removed once the infrastructure
59+
* have the ability to remove methods from parse tree once
60+
* such condition is met.
61+
*/
62+
if (!ib_dev->create_counters)
63+
return -EOPNOTSUPP;
64+
65+
uobj = uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_COUNTERS_HANDLE);
66+
counters = ib_dev->create_counters(ib_dev, attrs);
67+
if (IS_ERR(counters)) {
68+
ret = PTR_ERR(counters);
69+
goto err_create_counters;
70+
}
71+
72+
counters->device = ib_dev;
73+
counters->uobject = uobj;
74+
uobj->object = counters;
75+
atomic_set(&counters->usecnt, 0);
76+
77+
return 0;
78+
79+
err_create_counters:
80+
return ret;
81+
}
82+
83+
static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)(struct ib_device *ib_dev,
84+
struct ib_uverbs_file *file,
85+
struct uverbs_attr_bundle *attrs)
86+
{
87+
struct ib_counters_read_attr read_attr = {};
88+
const struct uverbs_attr *uattr;
89+
struct ib_counters *counters =
90+
uverbs_attr_get_obj(attrs, UVERBS_ATTR_READ_COUNTERS_HANDLE);
91+
int ret;
92+
93+
if (!ib_dev->read_counters)
94+
return -EOPNOTSUPP;
95+
96+
if (!atomic_read(&counters->usecnt))
97+
return -EINVAL;
98+
99+
ret = uverbs_copy_from(&read_attr.flags, attrs,
100+
UVERBS_ATTR_READ_COUNTERS_FLAGS);
101+
if (ret)
102+
return ret;
103+
104+
uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF);
105+
read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64);
106+
read_attr.counters_buff = kcalloc(read_attr.ncounters,
107+
sizeof(u64), GFP_KERNEL);
108+
if (!read_attr.counters_buff)
109+
return -ENOMEM;
110+
111+
ret = ib_dev->read_counters(counters,
112+
&read_attr,
113+
attrs);
114+
if (ret)
115+
goto err_read;
116+
117+
ret = uverbs_copy_to(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF,
118+
read_attr.counters_buff,
119+
read_attr.ncounters * sizeof(u64));
120+
121+
err_read:
122+
kfree(read_attr.counters_buff);
123+
return ret;
124+
}
125+
126+
static DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_COUNTERS_CREATE,
127+
&UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_COUNTERS_HANDLE,
128+
UVERBS_OBJECT_COUNTERS,
129+
UVERBS_ACCESS_NEW,
130+
UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));
131+
132+
static DECLARE_UVERBS_NAMED_METHOD_WITH_HANDLER(UVERBS_METHOD_COUNTERS_DESTROY,
133+
uverbs_destroy_def_handler,
134+
&UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_COUNTERS_HANDLE,
135+
UVERBS_OBJECT_COUNTERS,
136+
UVERBS_ACCESS_DESTROY,
137+
UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));
138+
139+
#define MAX_COUNTERS_BUFF_SIZE USHRT_MAX
140+
static DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_COUNTERS_READ,
141+
&UVERBS_ATTR_IDR(UVERBS_ATTR_READ_COUNTERS_HANDLE,
142+
UVERBS_OBJECT_COUNTERS,
143+
UVERBS_ACCESS_READ,
144+
UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)),
145+
&UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_READ_COUNTERS_BUFF,
146+
UVERBS_ATTR_SIZE(0, MAX_COUNTERS_BUFF_SIZE),
147+
UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)),
148+
&UVERBS_ATTR_PTR_IN(UVERBS_ATTR_READ_COUNTERS_FLAGS,
149+
UVERBS_ATTR_TYPE(__u32),
150+
UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));
151+
152+
DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_COUNTERS,
153+
&UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_counters),
154+
&UVERBS_METHOD(UVERBS_METHOD_COUNTERS_CREATE),
155+
&UVERBS_METHOD(UVERBS_METHOD_COUNTERS_DESTROY),
156+
&UVERBS_METHOD(UVERBS_METHOD_COUNTERS_READ));
157+

drivers/infiniband/core/uverbs_std_types_cq.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(struct ib_device *ib_dev,
6565
struct ib_cq_init_attr attr = {};
6666
struct ib_cq *cq;
6767
struct ib_uverbs_completion_event_file *ev_file = NULL;
68-
const struct uverbs_attr *ev_file_attr;
6968
struct ib_uobject *ev_file_uobj;
7069

7170
if (!(ib_dev->uverbs_cmd_mask & 1ULL << IB_USER_VERBS_CMD_CREATE_CQ))
@@ -87,10 +86,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(struct ib_device *ib_dev,
8786
UVERBS_ATTR_CREATE_CQ_FLAGS)))
8887
return -EFAULT;
8988

90-
ev_file_attr = uverbs_attr_get(attrs, UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL);
91-
if (!IS_ERR(ev_file_attr)) {
92-
ev_file_uobj = ev_file_attr->obj_attr.uobject;
93-
89+
ev_file_uobj = uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL);
90+
if (!IS_ERR(ev_file_uobj)) {
9491
ev_file = container_of(ev_file_uobj,
9592
struct ib_uverbs_completion_event_file,
9693
uobj_file.uobj);
@@ -102,8 +99,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(struct ib_device *ib_dev,
10299
goto err_event_file;
103100
}
104101

105-
obj = container_of(uverbs_attr_get(attrs,
106-
UVERBS_ATTR_CREATE_CQ_HANDLE)->obj_attr.uobject,
102+
obj = container_of(uverbs_attr_get_uobject(attrs,
103+
UVERBS_ATTR_CREATE_CQ_HANDLE),
107104
typeof(*obj), uobject);
108105
obj->uverbs_file = ucontext->ufile;
109106
obj->comp_events_reported = 0;
@@ -170,13 +167,17 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_DESTROY)(struct ib_device *ib_dev,
170167
struct ib_uverbs_file *file,
171168
struct uverbs_attr_bundle *attrs)
172169
{
173-
struct ib_uverbs_destroy_cq_resp resp;
174170
struct ib_uobject *uobj =
175-
uverbs_attr_get(attrs, UVERBS_ATTR_DESTROY_CQ_HANDLE)->obj_attr.uobject;
176-
struct ib_ucq_object *obj = container_of(uobj, struct ib_ucq_object,
177-
uobject);
171+
uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_CQ_HANDLE);
172+
struct ib_uverbs_destroy_cq_resp resp;
173+
struct ib_ucq_object *obj;
178174
int ret;
179175

176+
if (IS_ERR(uobj))
177+
return PTR_ERR(uobj);
178+
179+
obj = container_of(uobj, struct ib_ucq_object, uobject);
180+
180181
if (!(ib_dev->uverbs_cmd_mask & 1ULL << IB_USER_VERBS_CMD_DESTROY_CQ))
181182
return -EOPNOTSUPP;
182183

0 commit comments

Comments
 (0)