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

Commit 39661e2c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tc_action-ns'



Cong Wang says:

====================
net_sched: add network namespace support for tc actions

This patchset adds network namespace support for tc actions.

v2:
* pull the first patch into net-next
* reduce code duplication by introducing more helper functions
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 555d5b70 ddf97ccd
Loading
Loading
Loading
Loading
+47 −16
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@

#include <net/sch_generic.h>
#include <net/pkt_sched.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>

struct tcf_common {
	struct hlist_node		tcfc_head;
@@ -65,11 +67,6 @@ static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
	return 0;
}

static inline void tcf_hashinfo_destroy(struct tcf_hashinfo *hf)
{
	kfree(hf->htab);
}

/* Update lastuse only if needed, to avoid dirtying a cache line.
 * We use a temp variable to avoid fetching jiffies twice.
 */
@@ -92,31 +89,65 @@ struct tc_action {
	__u32			type; /* for backward compat(TCA_OLD_COMPAT) */
	__u32			order;
	struct list_head	list;
	struct tcf_hashinfo	*hinfo;
};

struct tc_action_ops {
	struct list_head head;
	struct tcf_hashinfo *hinfo;
	char    kind[IFNAMSIZ];
	__u32   type; /* TBD to match kind */
	struct module		*owner;
	int     (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *);
	int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
	void	(*cleanup)(struct tc_action *, int bind);
	int     (*lookup)(struct tc_action *, u32);
	int     (*lookup)(struct net *, struct tc_action *, u32);
	int     (*init)(struct net *net, struct nlattr *nla,
			struct nlattr *est, struct tc_action *act, int ovr,
			int bind);
	int     (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
	int     (*walk)(struct net *, struct sk_buff *,
			struct netlink_callback *, int, struct tc_action *);
};

int tcf_hash_search(struct tc_action *a, u32 index);
u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
int tcf_hash_check(u32 index, struct tc_action *a, int bind);
int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
		    int size, int bind, bool cpustats);
struct tc_action_net {
	struct tcf_hashinfo *hinfo;
	const struct tc_action_ops *ops;
};

static inline
int tc_action_net_init(struct tc_action_net *tn, const struct tc_action_ops *ops,
		       unsigned int mask)
{
	int err = 0;

	tn->hinfo = kmalloc(sizeof(*tn->hinfo), GFP_KERNEL);
	if (!tn->hinfo)
		return -ENOMEM;
	tn->ops = ops;
	err = tcf_hashinfo_init(tn->hinfo, mask);
	if (err)
		kfree(tn->hinfo);
	return err;
}

void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
			  struct tcf_hashinfo *hinfo);

static inline void tc_action_net_exit(struct tc_action_net *tn)
{
	tcf_hashinfo_destroy(tn->ops, tn->hinfo);
}

int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
		       struct tc_action *a);
int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index);
u32 tcf_hash_new_index(struct tc_action_net *tn);
int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
		   int bind);
int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		    struct tc_action *a, int size, int bind, bool cpustats);
void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
void tcf_hash_insert(struct tc_action *a);
void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a);

int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);

@@ -125,8 +156,8 @@ static inline int tcf_hash_release(struct tc_action *a, bool bind)
	return __tcf_hash_release(a, bind, false);
}

int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
int tcf_unregister_action(struct tc_action_ops *a);
int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops);
int tcf_action_destroy(struct list_head *actions, int bind);
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
		    struct tcf_result *res);
+83 −54
Original line number Diff line number Diff line
@@ -36,10 +36,9 @@ static void free_tcf(struct rcu_head *head)
	kfree(p);
}

static void tcf_hash_destroy(struct tc_action *a)
static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a)
{
	struct tcf_common *p = a->priv;
	struct tcf_hashinfo *hinfo = a->ops->hinfo;

	spin_lock_bh(&hinfo->lock);
	hlist_del(&p->tcfc_head);
@@ -68,8 +67,8 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
		if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
			if (a->ops->cleanup)
				a->ops->cleanup(a, bind);
			tcf_hash_destroy(a);
			ret = 1;
			tcf_hash_destroy(a->hinfo, a);
			ret = ACT_P_DELETED;
		}
	}

@@ -77,10 +76,9 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
}
EXPORT_SYMBOL(__tcf_hash_release);

static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
			   struct tc_action *a)
static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
			   struct netlink_callback *cb, struct tc_action *a)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct hlist_head *head;
	struct tcf_common *p;
	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
@@ -126,9 +124,9 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
	goto done;
}

static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
			  struct tc_action *a)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct hlist_head *head;
	struct hlist_node *n;
	struct tcf_common *p;
@@ -163,18 +161,24 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
	return ret;
}

static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
			      int type, struct tc_action *a)
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
		       struct tc_action *a)
{
	struct tcf_hashinfo *hinfo = tn->hinfo;

	a->hinfo = hinfo;

	if (type == RTM_DELACTION) {
		return tcf_del_walker(skb, a);
		return tcf_del_walker(hinfo, skb, a);
	} else if (type == RTM_GETACTION) {
		return tcf_dump_walker(skb, cb, a);
		return tcf_dump_walker(hinfo, skb, cb, a);
	} else {
		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
		return -EINVAL;
	}
}
EXPORT_SYMBOL(tcf_generic_walker);

static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
{
@@ -191,8 +195,9 @@ static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
	return p;
}

u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
u32 tcf_hash_new_index(struct tc_action_net *tn)
{
	struct tcf_hashinfo *hinfo = tn->hinfo;
	u32 val = hinfo->index;

	do {
@@ -205,28 +210,31 @@ u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
}
EXPORT_SYMBOL(tcf_hash_new_index);

int tcf_hash_search(struct tc_action *a, u32 index)
int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_common *p = tcf_hash_lookup(index, hinfo);

	if (p) {
		a->priv = p;
		a->hinfo = hinfo;
		return 1;
	}
	return 0;
}
EXPORT_SYMBOL(tcf_hash_search);

int tcf_hash_check(u32 index, struct tc_action *a, int bind)
int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
		   int bind)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_common *p = NULL;
	if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
		if (bind)
			p->tcfc_bindcnt++;
		p->tcfc_refcnt++;
		a->priv = p;
		a->hinfo = hinfo;
		return 1;
	}
	return 0;
@@ -243,11 +251,11 @@ void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
}
EXPORT_SYMBOL(tcf_hash_cleanup);

int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
		    int size, int bind, bool cpustats)
int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		    struct tc_action *a, int size, int bind, bool cpustats)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct tcf_common *p = kzalloc(size, GFP_KERNEL);
	struct tcf_hashinfo *hinfo = tn->hinfo;
	int err = -ENOMEM;

	if (unlikely(!p))
@@ -272,7 +280,7 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
	}
	spin_lock_init(&p->tcfc_lock);
	INIT_HLIST_NODE(&p->tcfc_head);
	p->tcfc_index = index ? index : tcf_hash_new_index(hinfo);
	p->tcfc_index = index ? index : tcf_hash_new_index(tn);
	p->tcfc_tm.install = jiffies;
	p->tcfc_tm.lastuse = jiffies;
	if (est) {
@@ -286,14 +294,15 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
	}

	a->priv = (void *) p;
	a->hinfo = hinfo;
	return 0;
}
EXPORT_SYMBOL(tcf_hash_create);

void tcf_hash_insert(struct tc_action *a)
void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a)
{
	struct tcf_common *p = a->priv;
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct tcf_hashinfo *hinfo = tn->hinfo;
	unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);

	spin_lock_bh(&hinfo->lock);
@@ -302,59 +311,78 @@ void tcf_hash_insert(struct tc_action *a)
}
EXPORT_SYMBOL(tcf_hash_insert);

void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
			  struct tcf_hashinfo *hinfo)
{
	struct tc_action a = {
		.ops = ops,
		.hinfo = hinfo,
	};
	int i;

	for (i = 0; i < hinfo->hmask + 1; i++) {
		struct tcf_common *p;
		struct hlist_node *n;

		hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfc_head) {
			int ret;

			a.priv = p;
			ret = __tcf_hash_release(&a, false, true);
			if (ret == ACT_P_DELETED)
				module_put(ops->owner);
			else if (ret < 0)
				return;
		}
	}
	kfree(hinfo->htab);
}
EXPORT_SYMBOL(tcf_hashinfo_destroy);

static LIST_HEAD(act_base);
static DEFINE_RWLOCK(act_mod_lock);

int tcf_register_action(struct tc_action_ops *act, unsigned int mask)
int tcf_register_action(struct tc_action_ops *act,
			struct pernet_operations *ops)
{
	struct tc_action_ops *a;
	int err;
	int ret;

	/* Must supply act, dump and init */
	if (!act->act || !act->dump || !act->init)
	if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
		return -EINVAL;

	/* Supply defaults */
	if (!act->lookup)
		act->lookup = tcf_hash_search;
	if (!act->walk)
		act->walk = tcf_generic_walker;

	act->hinfo = kmalloc(sizeof(struct tcf_hashinfo), GFP_KERNEL);
	if (!act->hinfo)
		return -ENOMEM;
	err = tcf_hashinfo_init(act->hinfo, mask);
	if (err) {
		kfree(act->hinfo);
		return err;
	}

	write_lock(&act_mod_lock);
	list_for_each_entry(a, &act_base, head) {
		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
			write_unlock(&act_mod_lock);
			tcf_hashinfo_destroy(act->hinfo);
			kfree(act->hinfo);
			return -EEXIST;
		}
	}
	list_add_tail(&act->head, &act_base);
	write_unlock(&act_mod_lock);

	ret = register_pernet_subsys(ops);
	if (ret) {
		tcf_unregister_action(act, ops);
		return ret;
	}

	return 0;
}
EXPORT_SYMBOL(tcf_register_action);

int tcf_unregister_action(struct tc_action_ops *act)
int tcf_unregister_action(struct tc_action_ops *act,
			  struct pernet_operations *ops)
{
	struct tc_action_ops *a;
	int err = -ENOENT;

	unregister_pernet_subsys(ops);

	write_lock(&act_mod_lock);
	list_for_each_entry(a, &act_base, head) {
		if (a == act) {
			list_del(&act->head);
			tcf_hashinfo_destroy(act->hinfo);
			kfree(act->hinfo);
			err = 0;
			break;
		}
@@ -721,8 +749,8 @@ static struct tc_action *create_a(int i)
	return act;
}

static struct tc_action *
tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
					  struct nlmsghdr *n, u32 portid)
{
	struct nlattr *tb[TCA_ACT_MAX + 1];
	struct tc_action *a;
@@ -749,7 +777,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
	if (a->ops == NULL) /* could happen in batch of actions */
		goto err_free;
	err = -ENOENT;
	if (a->ops->lookup(a, index) == 0)
	if (a->ops->lookup(net, a, index) == 0)
		goto err_mod;

	module_put(a->ops->owner);
@@ -819,7 +847,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
	if (nest == NULL)
		goto out_module_put;

	err = a.ops->walk(skb, &dcb, RTM_DELACTION, &a);
	err = a.ops->walk(net, skb, &dcb, RTM_DELACTION, &a);
	if (err < 0)
		goto out_module_put;
	if (err == 0)
@@ -897,7 +925,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
	}

	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
		act = tcf_action_get_1(tb[i], n, portid);
		act = tcf_action_get_1(net, tb[i], n, portid);
		if (IS_ERR(act)) {
			ret = PTR_ERR(act);
			goto err;
@@ -1044,6 +1072,7 @@ find_dump_kind(const struct nlmsghdr *n)
static int
tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct net *net = sock_net(skb->sk);
	struct nlmsghdr *nlh;
	unsigned char *b = skb_tail_pointer(skb);
	struct nlattr *nest;
@@ -1078,7 +1107,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
	if (nest == NULL)
		goto out_module_put;

	ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
	ret = a_o->walk(net, skb, cb, RTM_GETACTION, &a);
	if (ret < 0)
		goto out_module_put;

+47 −5
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ struct tcf_bpf_cfg {
	bool is_ebpf;
};

static int bpf_net_id;

static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act,
		   struct tcf_result *res)
{
@@ -275,6 +277,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
			struct nlattr *est, struct tc_action *act,
			int replace, int bind)
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);
	struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
	struct tcf_bpf_cfg cfg, old;
	struct tc_act_bpf *parm;
@@ -294,8 +297,8 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,

	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);

	if (!tcf_hash_check(parm->index, act, bind)) {
		ret = tcf_hash_create(parm->index, est, act,
	if (!tcf_hash_check(tn, parm->index, act, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, act,
				      sizeof(*prog), bind, true);
		if (ret < 0)
			return ret;
@@ -344,7 +347,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
	rcu_assign_pointer(prog->filter, cfg.filter);

	if (res == ACT_P_CREATED) {
		tcf_hash_insert(act);
		tcf_hash_insert(tn, act);
	} else {
		/* make sure the program being replaced is no longer executing */
		synchronize_rcu();
@@ -367,6 +370,22 @@ static void tcf_bpf_cleanup(struct tc_action *act, int bind)
	tcf_bpf_cfg_cleanup(&tmp);
}

static int tcf_bpf_walker(struct net *net, struct sk_buff *skb,
			  struct netlink_callback *cb, int type,
			  struct tc_action *a)
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);

	return tcf_generic_walker(tn, skb, cb, type, a);
}

static int tcf_bpf_search(struct net *net, struct tc_action *a, u32 index)
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);

	return tcf_hash_search(tn, a, index);
}

static struct tc_action_ops act_bpf_ops __read_mostly = {
	.kind		=	"bpf",
	.type		=	TCA_ACT_BPF,
@@ -375,16 +394,39 @@ static struct tc_action_ops act_bpf_ops __read_mostly = {
	.dump		=	tcf_bpf_dump,
	.cleanup	=	tcf_bpf_cleanup,
	.init		=	tcf_bpf_init,
	.walk		=	tcf_bpf_walker,
	.lookup		=	tcf_bpf_search,
};

static __net_init int bpf_init_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);

	return tc_action_net_init(tn, &act_bpf_ops, BPF_TAB_MASK);
}

static void __net_exit bpf_exit_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);

	tc_action_net_exit(tn);
}

static struct pernet_operations bpf_net_ops = {
	.init = bpf_init_net,
	.exit = bpf_exit_net,
	.id   = &bpf_net_id,
	.size = sizeof(struct tc_action_net),
};

static int __init bpf_init_module(void)
{
	return tcf_register_action(&act_bpf_ops, BPF_TAB_MASK);
	return tcf_register_action(&act_bpf_ops, &bpf_net_ops);
}

static void __exit bpf_cleanup_module(void)
{
	tcf_unregister_action(&act_bpf_ops);
	tcf_unregister_action(&act_bpf_ops, &bpf_net_ops);
}

module_init(bpf_init_module);
+48 −6
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@

#define CONNMARK_TAB_MASK     3

static int connmark_net_id;

static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
			struct tcf_result *res)
{
@@ -97,6 +99,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
			     struct nlattr *est, struct tc_action *a,
			     int ovr, int bind)
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);
	struct nlattr *tb[TCA_CONNMARK_MAX + 1];
	struct tcf_connmark_info *ci;
	struct tc_connmark *parm;
@@ -111,9 +114,9 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,

	parm = nla_data(tb[TCA_CONNMARK_PARMS]);

	if (!tcf_hash_check(parm->index, a, bind)) {
		ret = tcf_hash_create(parm->index, est, a, sizeof(*ci),
				      bind, false);
	if (!tcf_hash_check(tn, parm->index, a, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, a,
				      sizeof(*ci), bind, false);
		if (ret)
			return ret;

@@ -122,7 +125,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
		ci->net = net;
		ci->zone = parm->zone;

		tcf_hash_insert(a);
		tcf_hash_insert(tn, a);
		ret = ACT_P_CREATED;
	} else {
		ci = to_connmark(a);
@@ -169,6 +172,22 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
	return -1;
}

static int tcf_connmark_walker(struct net *net, struct sk_buff *skb,
			       struct netlink_callback *cb, int type,
			       struct tc_action *a)
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);

	return tcf_generic_walker(tn, skb, cb, type, a);
}

static int tcf_connmark_search(struct net *net, struct tc_action *a, u32 index)
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);

	return tcf_hash_search(tn, a, index);
}

static struct tc_action_ops act_connmark_ops = {
	.kind		=	"connmark",
	.type		=	TCA_ACT_CONNMARK,
@@ -176,16 +195,39 @@ static struct tc_action_ops act_connmark_ops = {
	.act		=	tcf_connmark,
	.dump		=	tcf_connmark_dump,
	.init		=	tcf_connmark_init,
	.walk		=	tcf_connmark_walker,
	.lookup		=	tcf_connmark_search,
};

static __net_init int connmark_init_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);

	return tc_action_net_init(tn, &act_connmark_ops, CONNMARK_TAB_MASK);
}

static void __net_exit connmark_exit_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);

	tc_action_net_exit(tn);
}

static struct pernet_operations connmark_net_ops = {
	.init = connmark_init_net,
	.exit = connmark_exit_net,
	.id   = &connmark_net_id,
	.size = sizeof(struct tc_action_net),
};

static int __init connmark_init_module(void)
{
	return tcf_register_action(&act_connmark_ops, CONNMARK_TAB_MASK);
	return tcf_register_action(&act_connmark_ops, &connmark_net_ops);
}

static void __exit connmark_cleanup_module(void)
{
	tcf_unregister_action(&act_connmark_ops);
	tcf_unregister_action(&act_connmark_ops, &connmark_net_ops);
}

module_init(connmark_init_module);
+51 −8
Original line number Diff line number Diff line
@@ -42,9 +42,13 @@ static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
	[TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
};

static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
			 struct tc_action *a, int ovr, int bind)
static int csum_net_id;

static int tcf_csum_init(struct net *net, struct nlattr *nla,
			 struct nlattr *est, struct tc_action *a, int ovr,
			 int bind)
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);
	struct nlattr *tb[TCA_CSUM_MAX + 1];
	struct tc_csum *parm;
	struct tcf_csum *p;
@@ -61,9 +65,9 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
		return -EINVAL;
	parm = nla_data(tb[TCA_CSUM_PARMS]);

	if (!tcf_hash_check(parm->index, a, bind)) {
		ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
				      bind, false);
	if (!tcf_hash_check(tn, parm->index, a, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, a,
				      sizeof(*p), bind, false);
		if (ret)
			return ret;
		ret = ACT_P_CREATED;
@@ -82,7 +86,7 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
	spin_unlock_bh(&p->tcf_lock);

	if (ret == ACT_P_CREATED)
		tcf_hash_insert(a);
		tcf_hash_insert(tn, a);

	return ret;
}
@@ -555,6 +559,22 @@ static int tcf_csum_dump(struct sk_buff *skb,
	return -1;
}

static int tcf_csum_walker(struct net *net, struct sk_buff *skb,
			   struct netlink_callback *cb, int type,
			   struct tc_action *a)
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);

	return tcf_generic_walker(tn, skb, cb, type, a);
}

static int tcf_csum_search(struct net *net, struct tc_action *a, u32 index)
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);

	return tcf_hash_search(tn, a, index);
}

static struct tc_action_ops act_csum_ops = {
	.kind		= "csum",
	.type		= TCA_ACT_CSUM,
@@ -562,6 +582,29 @@ static struct tc_action_ops act_csum_ops = {
	.act		= tcf_csum,
	.dump		= tcf_csum_dump,
	.init		= tcf_csum_init,
	.walk		= tcf_csum_walker,
	.lookup		= tcf_csum_search,
};

static __net_init int csum_init_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);

	return tc_action_net_init(tn, &act_csum_ops, CSUM_TAB_MASK);
}

static void __net_exit csum_exit_net(struct net *net)
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);

	tc_action_net_exit(tn);
}

static struct pernet_operations csum_net_ops = {
	.init = csum_init_net,
	.exit = csum_exit_net,
	.id   = &csum_net_id,
	.size = sizeof(struct tc_action_net),
};

MODULE_DESCRIPTION("Checksum updating actions");
@@ -569,12 +612,12 @@ MODULE_LICENSE("GPL");

static int __init csum_init_module(void)
{
	return tcf_register_action(&act_csum_ops, CSUM_TAB_MASK);
	return tcf_register_action(&act_csum_ops, &csum_net_ops);
}

static void __exit csum_cleanup_module(void)
{
	tcf_unregister_action(&act_csum_ops);
	tcf_unregister_action(&act_csum_ops, &csum_net_ops);
}

module_init(csum_init_module);
Loading