Commit eadb4148 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

net: cls_bpf: add support for marking filters as hardware-only



Add cls_bpf support for the TCA_CLS_FLAGS_SKIP_SW flag.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d01d45f
Loading
Loading
Loading
Loading
+25 −9
Original line number Original line Diff line number Diff line
@@ -28,7 +28,7 @@ MODULE_DESCRIPTION("TC BPF based classifier");


#define CLS_BPF_NAME_LEN	256
#define CLS_BPF_NAME_LEN	256
#define CLS_BPF_SUPPORTED_GEN_FLAGS		\
#define CLS_BPF_SUPPORTED_GEN_FLAGS		\
	TCA_CLS_FLAGS_SKIP_HW
	(TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)


struct cls_bpf_head {
struct cls_bpf_head {
	struct list_head plist;
	struct list_head plist;
@@ -96,7 +96,9 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,


		qdisc_skb_cb(skb)->tc_classid = prog->res.classid;
		qdisc_skb_cb(skb)->tc_classid = prog->res.classid;


		if (at_ingress) {
		if (tc_skip_sw(prog->gen_flags)) {
			filter_res = prog->exts_integrated ? TC_ACT_UNSPEC : 0;
		} else if (at_ingress) {
			/* It is safe to push/pull even if skb_shared() */
			/* It is safe to push/pull even if skb_shared() */
			__skb_push(skb, skb->mac_len);
			__skb_push(skb, skb->mac_len);
			bpf_compute_data_end(skb);
			bpf_compute_data_end(skb);
@@ -164,32 +166,42 @@ static int cls_bpf_offload_cmd(struct tcf_proto *tp, struct cls_bpf_prog *prog,
					     tp->protocol, &offload);
					     tp->protocol, &offload);
}
}


static void cls_bpf_offload(struct tcf_proto *tp, struct cls_bpf_prog *prog,
static int cls_bpf_offload(struct tcf_proto *tp, struct cls_bpf_prog *prog,
			   struct cls_bpf_prog *oldprog)
			   struct cls_bpf_prog *oldprog)
{
{
	struct net_device *dev = tp->q->dev_queue->dev;
	struct net_device *dev = tp->q->dev_queue->dev;
	struct cls_bpf_prog *obj = prog;
	struct cls_bpf_prog *obj = prog;
	enum tc_clsbpf_command cmd;
	enum tc_clsbpf_command cmd;
	bool skip_sw;
	int ret;

	skip_sw = tc_skip_sw(prog->gen_flags) ||
		(oldprog && tc_skip_sw(oldprog->gen_flags));


	if (oldprog && oldprog->offloaded) {
	if (oldprog && oldprog->offloaded) {
		if (tc_should_offload(dev, tp, prog->gen_flags)) {
		if (tc_should_offload(dev, tp, prog->gen_flags)) {
			cmd = TC_CLSBPF_REPLACE;
			cmd = TC_CLSBPF_REPLACE;
		} else {
		} else if (!tc_skip_sw(prog->gen_flags)) {
			obj = oldprog;
			obj = oldprog;
			cmd = TC_CLSBPF_DESTROY;
			cmd = TC_CLSBPF_DESTROY;
		} else {
			return -EINVAL;
		}
		}
	} else {
	} else {
		if (!tc_should_offload(dev, tp, prog->gen_flags))
		if (!tc_should_offload(dev, tp, prog->gen_flags))
			return;
			return skip_sw ? -EINVAL : 0;
		cmd = TC_CLSBPF_ADD;
		cmd = TC_CLSBPF_ADD;
	}
	}


	if (cls_bpf_offload_cmd(tp, obj, cmd))
	ret = cls_bpf_offload_cmd(tp, obj, cmd);
		return;
	if (ret)
		return skip_sw ? ret : 0;


	obj->offloaded = true;
	obj->offloaded = true;
	if (oldprog)
	if (oldprog)
		oldprog->offloaded = false;
		oldprog->offloaded = false;

	return 0;
}
}


static void cls_bpf_stop_offload(struct tcf_proto *tp,
static void cls_bpf_stop_offload(struct tcf_proto *tp,
@@ -498,7 +510,11 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
	if (ret < 0)
	if (ret < 0)
		goto errout;
		goto errout;


	cls_bpf_offload(tp, prog, oldprog);
	ret = cls_bpf_offload(tp, prog, oldprog);
	if (ret) {
		cls_bpf_delete_prog(tp, prog);
		return ret;
	}


	if (oldprog) {
	if (oldprog) {
		list_replace_rcu(&oldprog->link, &prog->link);
		list_replace_rcu(&oldprog->link, &prog->link);