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

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

net: cls_bpf: add hardware offload



This patch adds hardware offload capability to cls_bpf classifier,
similar to what have been done with U32 and flower.

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 2d7a8926
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -789,6 +789,7 @@ enum {
	TC_SETUP_CLSU32,
	TC_SETUP_CLSFLOWER,
	TC_SETUP_MATCHALL,
	TC_SETUP_CLSBPF,
};

struct tc_cls_u32_offload;
@@ -800,6 +801,7 @@ struct tc_to_netdev {
		struct tc_cls_u32_offload *cls_u32;
		struct tc_cls_flower_offload *cls_flower;
		struct tc_cls_matchall_offload *cls_mall;
		struct tc_cls_bpf_offload *cls_bpf;
	};
};

+14 −0
Original line number Diff line number Diff line
@@ -486,4 +486,18 @@ struct tc_cls_matchall_offload {
	unsigned long cookie;
};

enum tc_clsbpf_command {
	TC_CLSBPF_ADD,
	TC_CLSBPF_REPLACE,
	TC_CLSBPF_DESTROY,
};

struct tc_cls_bpf_offload {
	enum tc_clsbpf_command command;
	struct tcf_exts *exts;
	struct bpf_prog *prog;
	const char *name;
	bool exts_integrated;
};

#endif
+70 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct cls_bpf_prog {
	struct list_head link;
	struct tcf_result res;
	bool exts_integrated;
	bool offloaded;
	struct tcf_exts exts;
	u32 handle;
	union {
@@ -138,6 +139,71 @@ static bool cls_bpf_is_ebpf(const struct cls_bpf_prog *prog)
	return !prog->bpf_ops;
}

static int cls_bpf_offload_cmd(struct tcf_proto *tp, struct cls_bpf_prog *prog,
			       enum tc_clsbpf_command cmd)
{
	struct net_device *dev = tp->q->dev_queue->dev;
	struct tc_cls_bpf_offload bpf_offload = {};
	struct tc_to_netdev offload;

	offload.type = TC_SETUP_CLSBPF;
	offload.cls_bpf = &bpf_offload;

	bpf_offload.command = cmd;
	bpf_offload.exts = &prog->exts;
	bpf_offload.prog = prog->filter;
	bpf_offload.name = prog->bpf_name;
	bpf_offload.exts_integrated = prog->exts_integrated;

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

static void 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;

	if (oldprog && oldprog->offloaded) {
		if (tc_should_offload(dev, tp, 0)) {
			cmd = TC_CLSBPF_REPLACE;
		} else {
			obj = oldprog;
			cmd = TC_CLSBPF_DESTROY;
		}
	} else {
		if (!tc_should_offload(dev, tp, 0))
			return;
		cmd = TC_CLSBPF_ADD;
	}

	if (cls_bpf_offload_cmd(tp, obj, cmd))
		return;

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

static void cls_bpf_stop_offload(struct tcf_proto *tp,
				 struct cls_bpf_prog *prog)
{
	int err;

	if (!prog->offloaded)
		return;

	err = cls_bpf_offload_cmd(tp, prog, TC_CLSBPF_DESTROY);
	if (err) {
		pr_err("Stopping hardware offload failed: %d\n", err);
		return;
	}

	prog->offloaded = false;
}

static int cls_bpf_init(struct tcf_proto *tp)
{
	struct cls_bpf_head *head;
@@ -177,6 +243,7 @@ static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg)
{
	struct cls_bpf_prog *prog = (struct cls_bpf_prog *) arg;

	cls_bpf_stop_offload(tp, prog);
	list_del_rcu(&prog->link);
	tcf_unbind_filter(tp, &prog->res);
	call_rcu(&prog->rcu, __cls_bpf_delete_prog);
@@ -193,6 +260,7 @@ static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
		return false;

	list_for_each_entry_safe(prog, tmp, &head->plist, link) {
		cls_bpf_stop_offload(tp, prog);
		list_del_rcu(&prog->link);
		tcf_unbind_filter(tp, &prog->res);
		call_rcu(&prog->rcu, __cls_bpf_delete_prog);
@@ -415,6 +483,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
	if (ret < 0)
		goto errout;

	cls_bpf_offload(tp, prog, oldprog);

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