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

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 Diff line number Diff line
@@ -28,7 +28,7 @@ MODULE_DESCRIPTION("TC BPF based classifier");

#define CLS_BPF_NAME_LEN	256
#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 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;

		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() */
			__skb_push(skb, skb->mac_len);
			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);
}

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 net_device *dev = tp->q->dev_queue->dev;
	struct cls_bpf_prog *obj = prog;
	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 (tc_should_offload(dev, tp, prog->gen_flags)) {
			cmd = TC_CLSBPF_REPLACE;
		} else {
		} else if (!tc_skip_sw(prog->gen_flags)) {
			obj = oldprog;
			cmd = TC_CLSBPF_DESTROY;
		} else {
			return -EINVAL;
		}
	} else {
		if (!tc_should_offload(dev, tp, prog->gen_flags))
			return;
			return skip_sw ? -EINVAL : 0;
		cmd = TC_CLSBPF_ADD;
	}

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

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

	return 0;
}

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)
		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) {
		list_replace_rcu(&oldprog->link, &prog->link);