Commit 9b828441 authored by Matan Barak's avatar Matan Barak Committed by Jason Gunthorpe

IB/uverbs: Add action_handle flow steering specification

Binding a flow_action to flow steering rule requires using a new
specification. Therefore, adding such an IB_FLOW_SPEC_ACTION_HANDLE flow
specification.

Flow steering rules could use flow_action(s) and as of that we need to
avoid deleting flow_action(s) as long as they're being used.
Moreover, when the attached rules are deleted, action_handle reference
count should be decremented. Introducing a new mechanism of flow
resources to keep track on the attached action_handle(s). Later on, this
mechanism should be extended to other attached flow steering resources
like flow counters.
Reviewed-by: default avatarYishai Hadas <yishaih@mellanox.com>
Signed-off-by: default avatarMatan Barak <matanb@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 2eb9beae
...@@ -203,11 +203,18 @@ struct ib_ucq_object { ...@@ -203,11 +203,18 @@ struct ib_ucq_object {
u32 async_events_reported; u32 async_events_reported;
}; };
struct ib_uflow_resources;
struct ib_uflow_object {
struct ib_uobject uobject;
struct ib_uflow_resources *resources;
};
extern const struct file_operations uverbs_event_fops; extern const struct file_operations uverbs_event_fops;
void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue); void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue);
struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file, struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file,
struct ib_device *ib_dev); struct ib_device *ib_dev);
void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file); void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file);
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res);
void ib_uverbs_release_ucq(struct ib_uverbs_file *file, void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
struct ib_uverbs_completion_event_file *ev_file, struct ib_uverbs_completion_event_file *ev_file,
...@@ -254,6 +261,7 @@ struct ib_uverbs_flow_spec { ...@@ -254,6 +261,7 @@ struct ib_uverbs_flow_spec {
struct ib_uverbs_flow_spec_ipv6 ipv6; struct ib_uverbs_flow_spec_ipv6 ipv6;
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;
}; };
}; };
......
...@@ -2739,8 +2739,52 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, ...@@ -2739,8 +2739,52 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
return ret ? ret : in_len; return ret ? ret : in_len;
} }
static int kern_spec_to_ib_spec_action(struct ib_uverbs_flow_spec *kern_spec, struct ib_uflow_resources {
union ib_flow_spec *ib_spec) size_t max;
size_t num;
struct ib_flow_action *collection[0];
};
static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
{
struct ib_uflow_resources *resources;
resources =
kmalloc(sizeof(*resources) +
num_specs * sizeof(*resources->collection), GFP_KERNEL);
if (!resources)
return NULL;
resources->num = 0;
resources->max = num_specs;
return resources;
}
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
{
unsigned int i;
for (i = 0; i < uflow_res->num; i++)
atomic_dec(&uflow_res->collection[i]->usecnt);
kfree(uflow_res);
}
static void flow_resources_add(struct ib_uflow_resources *uflow_res,
struct ib_flow_action *action)
{
WARN_ON(uflow_res->num >= uflow_res->max);
atomic_inc(&action->usecnt);
uflow_res->collection[uflow_res->num++] = action;
}
static int kern_spec_to_ib_spec_action(struct ib_ucontext *ucontext,
struct ib_uverbs_flow_spec *kern_spec,
union ib_flow_spec *ib_spec,
struct ib_uflow_resources *uflow_res)
{ {
ib_spec->type = kern_spec->type; ib_spec->type = kern_spec->type;
switch (ib_spec->type) { switch (ib_spec->type) {
...@@ -2759,6 +2803,21 @@ static int kern_spec_to_ib_spec_action(struct ib_uverbs_flow_spec *kern_spec, ...@@ -2759,6 +2803,21 @@ static int kern_spec_to_ib_spec_action(struct ib_uverbs_flow_spec *kern_spec,
ib_spec->drop.size = sizeof(struct ib_flow_spec_action_drop); ib_spec->drop.size = sizeof(struct ib_flow_spec_action_drop);
break; break;
case IB_FLOW_SPEC_ACTION_HANDLE:
if (kern_spec->action.size !=
sizeof(struct ib_uverbs_flow_spec_action_handle))
return -EOPNOTSUPP;
ib_spec->action.act = uobj_get_obj_read(flow_action,
UVERBS_OBJECT_FLOW_ACTION,
kern_spec->action.handle,
ucontext);
if (!ib_spec->action.act)
return -EINVAL;
ib_spec->action.size =
sizeof(struct ib_flow_spec_action_handle);
flow_resources_add(uflow_res, ib_spec->action.act);
uobj_put_obj_read(ib_spec->action.act);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -2900,14 +2959,17 @@ static int kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec *kern_spec, ...@@ -2900,14 +2959,17 @@ static int kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec *kern_spec,
kern_filter_sz, ib_spec); kern_filter_sz, ib_spec);
} }
static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, static int kern_spec_to_ib_spec(struct ib_ucontext *ucontext,
union ib_flow_spec *ib_spec) struct ib_uverbs_flow_spec *kern_spec,
union ib_flow_spec *ib_spec,
struct ib_uflow_resources *uflow_res)
{ {
if (kern_spec->reserved) if (kern_spec->reserved)
return -EINVAL; return -EINVAL;
if (kern_spec->type >= IB_FLOW_SPEC_ACTION_TAG) if (kern_spec->type >= IB_FLOW_SPEC_ACTION_TAG)
return kern_spec_to_ib_spec_action(kern_spec, ib_spec); return kern_spec_to_ib_spec_action(ucontext, kern_spec, ib_spec,
uflow_res);
else else
return kern_spec_to_ib_spec_filter(kern_spec, ib_spec); return kern_spec_to_ib_spec_filter(kern_spec, ib_spec);
} }
...@@ -3322,10 +3384,12 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, ...@@ -3322,10 +3384,12 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
struct ib_uverbs_create_flow cmd; struct ib_uverbs_create_flow cmd;
struct ib_uverbs_create_flow_resp resp; struct ib_uverbs_create_flow_resp resp;
struct ib_uobject *uobj; struct ib_uobject *uobj;
struct ib_uflow_object *uflow;
struct ib_flow *flow_id; struct ib_flow *flow_id;
struct ib_uverbs_flow_attr *kern_flow_attr; struct ib_uverbs_flow_attr *kern_flow_attr;
struct ib_flow_attr *flow_attr; struct ib_flow_attr *flow_attr;
struct ib_qp *qp; struct ib_qp *qp;
struct ib_uflow_resources *uflow_res;
int err = 0; int err = 0;
void *kern_spec; void *kern_spec;
void *ib_spec; void *ib_spec;
...@@ -3403,6 +3467,11 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, ...@@ -3403,6 +3467,11 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
err = -ENOMEM; err = -ENOMEM;
goto err_put; goto err_put;
} }
uflow_res = flow_resources_alloc(cmd.flow_attr.num_of_specs);
if (!uflow_res) {
err = -ENOMEM;
goto err_free_flow_attr;
}
flow_attr->type = kern_flow_attr->type; flow_attr->type = kern_flow_attr->type;
flow_attr->priority = kern_flow_attr->priority; flow_attr->priority = kern_flow_attr->priority;
...@@ -3417,7 +3486,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, ...@@ -3417,7 +3486,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
cmd.flow_attr.size > offsetof(struct ib_uverbs_flow_spec, reserved) && cmd.flow_attr.size > offsetof(struct ib_uverbs_flow_spec, reserved) &&
cmd.flow_attr.size >= cmd.flow_attr.size >=
((struct ib_uverbs_flow_spec *)kern_spec)->size; i++) { ((struct ib_uverbs_flow_spec *)kern_spec)->size; i++) {
err = kern_spec_to_ib_spec(kern_spec, ib_spec); err = kern_spec_to_ib_spec(file->ucontext, kern_spec, ib_spec,
uflow_res);
if (err) if (err)
goto err_free; goto err_free;
flow_attr->size += flow_attr->size +=
...@@ -3439,6 +3509,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, ...@@ -3439,6 +3509,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
} }
flow_id->uobject = uobj; flow_id->uobject = uobj;
uobj->object = flow_id; uobj->object = flow_id;
uflow = container_of(uobj, typeof(*uflow), uobject);
uflow->resources = uflow_res;
memset(&resp, 0, sizeof(resp)); memset(&resp, 0, sizeof(resp));
resp.flow_handle = uobj->id; resp.flow_handle = uobj->id;
...@@ -3457,6 +3529,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, ...@@ -3457,6 +3529,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
err_copy: err_copy:
ib_destroy_flow(flow_id); ib_destroy_flow(flow_id);
err_free: err_free:
ib_uverbs_flow_resources_free(uflow_res);
err_free_flow_attr:
kfree(flow_attr); kfree(flow_attr);
err_put: err_put:
uobj_put_obj_read(qp); uobj_put_obj_read(qp);
......
...@@ -48,7 +48,16 @@ static int uverbs_free_ah(struct ib_uobject *uobject, ...@@ -48,7 +48,16 @@ static int uverbs_free_ah(struct ib_uobject *uobject,
static int uverbs_free_flow(struct ib_uobject *uobject, static int uverbs_free_flow(struct ib_uobject *uobject,
enum rdma_remove_reason why) enum rdma_remove_reason why)
{ {
return ib_destroy_flow((struct ib_flow *)uobject->object); int ret;
struct ib_flow *flow = (struct ib_flow *)uobject->object;
struct ib_uflow_object *uflow =
container_of(uobject, struct ib_uflow_object, uobject);
ret = ib_destroy_flow(flow);
if (!ret)
ib_uverbs_flow_resources_free(uflow->resources);
return ret;
} }
static int uverbs_free_mw(struct ib_uobject *uobject, static int uverbs_free_mw(struct ib_uobject *uobject,
...@@ -268,7 +277,8 @@ DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_AH, ...@@ -268,7 +277,8 @@ DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_AH,
&UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_ah)); &UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_ah));
DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_FLOW, DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_FLOW,
&UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_flow)); &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uflow_object),
0, uverbs_free_flow));
DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_WQ, DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_WQ,
&UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uwq_object), 0, &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uwq_object), 0,
......
...@@ -1836,6 +1836,7 @@ enum ib_flow_spec_type { ...@@ -1836,6 +1836,7 @@ enum ib_flow_spec_type {
/* Actions */ /* Actions */
IB_FLOW_SPEC_ACTION_TAG = 0x1000, IB_FLOW_SPEC_ACTION_TAG = 0x1000,
IB_FLOW_SPEC_ACTION_DROP = 0x1001, IB_FLOW_SPEC_ACTION_DROP = 0x1001,
IB_FLOW_SPEC_ACTION_HANDLE = 0x1002,
}; };
#define IB_FLOW_SPEC_LAYER_MASK 0xF0 #define IB_FLOW_SPEC_LAYER_MASK 0xF0
#define IB_FLOW_SPEC_SUPPORT_LAYERS 8 #define IB_FLOW_SPEC_SUPPORT_LAYERS 8
...@@ -1969,6 +1970,12 @@ struct ib_flow_spec_action_drop { ...@@ -1969,6 +1970,12 @@ struct ib_flow_spec_action_drop {
u16 size; u16 size;
}; };
struct ib_flow_spec_action_handle {
enum ib_flow_spec_type type;
u16 size;
struct ib_flow_action *act;
};
union ib_flow_spec { union ib_flow_spec {
struct { struct {
u32 type; u32 type;
...@@ -1982,6 +1989,7 @@ union ib_flow_spec { ...@@ -1982,6 +1989,7 @@ union ib_flow_spec {
struct ib_flow_spec_tunnel tunnel; struct ib_flow_spec_tunnel tunnel;
struct ib_flow_spec_action_tag flow_tag; struct ib_flow_spec_action_tag flow_tag;
struct ib_flow_spec_action_drop drop; struct ib_flow_spec_action_drop drop;
struct ib_flow_spec_action_handle action;
}; };
struct ib_flow_attr { struct ib_flow_attr {
......
...@@ -984,6 +984,19 @@ struct ib_uverbs_flow_spec_action_drop { ...@@ -984,6 +984,19 @@ struct ib_uverbs_flow_spec_action_drop {
}; };
}; };
struct ib_uverbs_flow_spec_action_handle {
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;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment