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

Commit b87f7936 authored by Yotam Gigi's avatar Yotam Gigi Committed by David S. Miller
Browse files

net/sched: Add match-all classifier hw offloading.



Following the work that have been done on offloading classifiers like u32
and flower, now the match-all classifier hw offloading is possible. if
the interface supports tc offloading.

To control the offloading, two tc flags have been introduced: skip_sw and
skip_hw. Typical usage:

tc filter add dev eth25 parent ffff: 	\
	matchall skip_sw		\
	action mirred egress mirror	\
	dev eth27

Signed-off-by: default avatarYotam Gigi <yotamg@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bf3994d2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -787,6 +787,7 @@ enum {
	TC_SETUP_MQPRIO,
	TC_SETUP_CLSU32,
	TC_SETUP_CLSFLOWER,
	TC_SETUP_MATCHALL,
};

struct tc_cls_u32_offload;
@@ -797,6 +798,7 @@ struct tc_to_netdev {
		u8 tc;
		struct tc_cls_u32_offload *cls_u32;
		struct tc_cls_flower_offload *cls_flower;
		struct tc_cls_matchall_offload *cls_mall;
	};
};

+11 −0
Original line number Diff line number Diff line
@@ -442,4 +442,15 @@ struct tc_cls_flower_offload {
	struct tcf_exts *exts;
};

enum tc_matchall_command {
	TC_CLSMATCHALL_REPLACE,
	TC_CLSMATCHALL_DESTROY,
};

struct tc_cls_matchall_offload {
	enum tc_matchall_command command;
	struct tcf_exts *exts;
	unsigned long cookie;
};

#endif
+1 −0
Original line number Diff line number Diff line
@@ -439,6 +439,7 @@ enum {
	TCA_MATCHALL_UNSPEC,
	TCA_MATCHALL_CLASSID,
	TCA_MATCHALL_ACT,
	TCA_MATCHALL_FLAGS,
	__TCA_MATCHALL_MAX,
};

+73 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ struct cls_mall_filter {
	struct tcf_result res;
	u32 handle;
	struct rcu_head	rcu;
	u32 flags;
};

struct cls_mall_head {
@@ -34,6 +35,9 @@ static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
	struct cls_mall_head *head = rcu_dereference_bh(tp->root);
	struct cls_mall_filter *f = head->filter;

	if (tc_skip_sw(f->flags))
		return -1;

	return tcf_exts_exec(skb, &f->exts, res);
}

@@ -55,18 +59,61 @@ static void mall_destroy_filter(struct rcu_head *head)
	struct cls_mall_filter *f = container_of(head, struct cls_mall_filter, rcu);

	tcf_exts_destroy(&f->exts);

	kfree(f);
}

static int mall_replace_hw_filter(struct tcf_proto *tp,
				  struct cls_mall_filter *f,
				  unsigned long cookie)
{
	struct net_device *dev = tp->q->dev_queue->dev;
	struct tc_to_netdev offload;
	struct tc_cls_matchall_offload mall_offload = {0};

	offload.type = TC_SETUP_MATCHALL;
	offload.cls_mall = &mall_offload;
	offload.cls_mall->command = TC_CLSMATCHALL_REPLACE;
	offload.cls_mall->exts = &f->exts;
	offload.cls_mall->cookie = cookie;

	return dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
					     &offload);
}

static void mall_destroy_hw_filter(struct tcf_proto *tp,
				   struct cls_mall_filter *f,
				   unsigned long cookie)
{
	struct net_device *dev = tp->q->dev_queue->dev;
	struct tc_to_netdev offload;
	struct tc_cls_matchall_offload mall_offload = {0};

	offload.type = TC_SETUP_MATCHALL;
	offload.cls_mall = &mall_offload;
	offload.cls_mall->command = TC_CLSMATCHALL_DESTROY;
	offload.cls_mall->exts = NULL;
	offload.cls_mall->cookie = cookie;

	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
					     &offload);
}

static bool mall_destroy(struct tcf_proto *tp, bool force)
{
	struct cls_mall_head *head = rtnl_dereference(tp->root);
	struct net_device *dev = tp->q->dev_queue->dev;
	struct cls_mall_filter *f = head->filter;

	if (!force && head->filter)
	if (!force && f)
		return false;

	if (head->filter)
		call_rcu(&head->filter->rcu, mall_destroy_filter);
	if (f) {
		if (tc_should_offload(dev, tp, f->flags))
			mall_destroy_hw_filter(tp, f, (unsigned long) f);

		call_rcu(&f->rcu, mall_destroy_filter);
	}
	RCU_INIT_POINTER(tp->root, NULL);
	kfree_rcu(head, rcu);
	return true;
@@ -117,8 +164,10 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
{
	struct cls_mall_head *head = rtnl_dereference(tp->root);
	struct cls_mall_filter *fold = (struct cls_mall_filter *) *arg;
	struct net_device *dev = tp->q->dev_queue->dev;
	struct cls_mall_filter *f;
	struct nlattr *tb[TCA_MATCHALL_MAX + 1];
	u32 flags = 0;
	int err;

	if (!tca[TCA_OPTIONS])
@@ -135,6 +184,12 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
	if (err < 0)
		return err;

	if (tb[TCA_MATCHALL_FLAGS]) {
		flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
		if (!tc_flags_valid(flags))
			return -EINVAL;
	}

	f = kzalloc(sizeof(*f), GFP_KERNEL);
	if (!f)
		return -ENOBUFS;
@@ -144,11 +199,22 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
	if (!handle)
		handle = 1;
	f->handle = handle;
	f->flags = flags;

	err = mall_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
	if (err)
		goto errout;

	if (tc_should_offload(dev, tp, flags)) {
		err = mall_replace_hw_filter(tp, f, (unsigned long) f);
		if (err) {
			if (tc_skip_sw(flags))
				goto errout;
			else
				err = 0;
		}
	}

	*arg = (unsigned long) f;
	rcu_assign_pointer(head->filter, f);

@@ -163,6 +229,10 @@ static int mall_delete(struct tcf_proto *tp, unsigned long arg)
{
	struct cls_mall_head *head = rtnl_dereference(tp->root);
	struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
	struct net_device *dev = tp->q->dev_queue->dev;

	if (tc_should_offload(dev, tp, f->flags))
		mall_destroy_hw_filter(tp, f, (unsigned long) f);

	RCU_INIT_POINTER(head->filter, NULL);
	tcf_unbind_filter(tp, &f->res);