Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6ba4a9a authored by Raed Salem's avatar Raed Salem Committed by Leon Romanovsky
Browse files

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: default avatarYishai Hadas <yishaih@mellanox.com>
Signed-off-by: default avatarRaed Salem <raeds@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 7eea23a5
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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;
	};
	};
};
};


+70 −11
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}
+13 −0
Original line number Original line Diff line number Diff line
@@ -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;
};
};