IB/uverbs: Add support for flow counters

The struct ib_uverbs_flow_spec_action_count associates a counters object
with the flow.

Post this association the flow counters can be read via the counters
object.

Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Raed Salem <raeds@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
Raed Salem 2018-05-31 16:43:37 +03:00 committed by Leon Romanovsky
parent 7eea23a5cd
commit b6ba4a9aa5
3 changed files with 84 additions and 11 deletions

View File

@ -263,6 +263,7 @@ struct ib_uverbs_flow_spec {
struct ib_uverbs_flow_spec_action_tag flow_tag; struct ib_uverbs_flow_spec_action_tag flow_tag;
struct ib_uverbs_flow_spec_action_drop drop; struct ib_uverbs_flow_spec_action_drop drop;
struct ib_uverbs_flow_spec_action_handle action; struct ib_uverbs_flow_spec_action_handle action;
struct ib_uverbs_flow_spec_action_count flow_count;
}; };
}; };

View File

@ -2742,43 +2742,82 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
struct ib_uflow_resources { struct ib_uflow_resources {
size_t max; size_t max;
size_t num; size_t num;
struct ib_flow_action *collection[0]; size_t collection_num;
size_t counters_num;
struct ib_counters **counters;
struct ib_flow_action **collection;
}; };
static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs) static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
{ {
struct ib_uflow_resources *resources; struct ib_uflow_resources *resources;
resources = resources = kzalloc(sizeof(*resources), GFP_KERNEL);
kmalloc(sizeof(*resources) +
num_specs * sizeof(*resources->collection), GFP_KERNEL);
if (!resources) if (!resources)
return NULL; goto err_res;
resources->counters =
kcalloc(num_specs, sizeof(*resources->counters), GFP_KERNEL);
if (!resources->counters)
goto err_cnt;
resources->collection =
kcalloc(num_specs, sizeof(*resources->collection), GFP_KERNEL);
if (!resources->collection)
goto err_collection;
resources->num = 0;
resources->max = num_specs; resources->max = num_specs;
return resources; return resources;
err_collection:
kfree(resources->counters);
err_cnt:
kfree(resources);
err_res:
return NULL;
} }
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res) void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < uflow_res->num; i++) for (i = 0; i < uflow_res->collection_num; i++)
atomic_dec(&uflow_res->collection[i]->usecnt); atomic_dec(&uflow_res->collection[i]->usecnt);
for (i = 0; i < uflow_res->counters_num; i++)
atomic_dec(&uflow_res->counters[i]->usecnt);
kfree(uflow_res->collection);
kfree(uflow_res->counters);
kfree(uflow_res); kfree(uflow_res);
} }
static void flow_resources_add(struct ib_uflow_resources *uflow_res, static void flow_resources_add(struct ib_uflow_resources *uflow_res,
struct ib_flow_action *action) enum ib_flow_spec_type type,
void *ibobj)
{ {
WARN_ON(uflow_res->num >= uflow_res->max); WARN_ON(uflow_res->num >= uflow_res->max);
atomic_inc(&action->usecnt); switch (type) {
uflow_res->collection[uflow_res->num++] = action; case IB_FLOW_SPEC_ACTION_HANDLE:
atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
uflow_res->collection[uflow_res->collection_num++] =
(struct ib_flow_action *)ibobj;
break;
case IB_FLOW_SPEC_ACTION_COUNT:
atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
uflow_res->counters[uflow_res->counters_num++] =
(struct ib_counters *)ibobj;
break;
default:
WARN_ON(1);
}
uflow_res->num++;
} }
static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext, static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext,
@ -2815,9 +2854,29 @@ static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext,
return -EINVAL; return -EINVAL;
ib_spec->action.size = ib_spec->action.size =
sizeof(struct ib_flow_spec_action_handle); sizeof(struct ib_flow_spec_action_handle);
flow_resources_add(uflow_res, ib_spec->action.act); flow_resources_add(uflow_res,
IB_FLOW_SPEC_ACTION_HANDLE,
ib_spec->action.act);
uobj_put_obj_read(ib_spec->action.act); uobj_put_obj_read(ib_spec->action.act);
break; break;
case IB_FLOW_SPEC_ACTION_COUNT:
if (kern_spec->flow_count.size !=
sizeof(struct ib_uverbs_flow_spec_action_count))
return -EINVAL;
ib_spec->flow_count.counters =
uobj_get_obj_read(counters,
UVERBS_OBJECT_COUNTERS,
kern_spec->flow_count.handle,
ucontext);
if (!ib_spec->flow_count.counters)
return -EINVAL;
ib_spec->flow_count.size =
sizeof(struct ib_flow_spec_action_count);
flow_resources_add(uflow_res,
IB_FLOW_SPEC_ACTION_COUNT,
ib_spec->flow_count.counters);
uobj_put_obj_read(ib_spec->flow_count.counters);
break;
default: default:
return -EINVAL; return -EINVAL;
} }

View File

@ -998,6 +998,19 @@ struct ib_uverbs_flow_spec_action_handle {
__u32 reserved1; __u32 reserved1;
}; };
struct ib_uverbs_flow_spec_action_count {
union {
struct ib_uverbs_flow_spec_hdr hdr;
struct {
__u32 type;
__u16 size;
__u16 reserved;
};
};
__u32 handle;
__u32 reserved1;
};
struct ib_uverbs_flow_tunnel_filter { struct ib_uverbs_flow_tunnel_filter {
__be32 tunnel_id; __be32 tunnel_id;
}; };