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

Commit 65a206c0 authored by Chris Mi's avatar Chris Mi Committed by David S. Miller
Browse files

net/sched: Change act_api and act_xxx modules to use IDR



Typically, each TC filter has its own action. All the actions of the
same type are saved in its hash table. But the hash buckets are too
small that it degrades to a list. And the performance is greatly
affected. For example, it takes about 0m11.914s to insert 64K rules.
If we convert the hash table to IDR, it only takes about 0m1.500s.
The improvement is huge.

But please note that the test result is based on previous patch that
cls_flower uses IDR.

Signed-off-by: default avatarChris Mi <chrism@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c15ab236
Loading
Loading
Loading
Loading
+24 −52
Original line number Original line Diff line number Diff line
@@ -10,12 +10,9 @@
#include <net/net_namespace.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/netns/generic.h>



struct tcf_idrinfo {
struct tcf_hashinfo {
	struct hlist_head	*htab;
	unsigned int		hmask;
	spinlock_t	lock;
	spinlock_t	lock;
	u32			index;
	struct idr	action_idr;
};
};


struct tc_action_ops;
struct tc_action_ops;
@@ -25,9 +22,8 @@ struct tc_action {
	__u32				type; /* for backward compat(TCA_OLD_COMPAT) */
	__u32				type; /* for backward compat(TCA_OLD_COMPAT) */
	__u32				order;
	__u32				order;
	struct list_head		list;
	struct list_head		list;
	struct tcf_hashinfo		*hinfo;
	struct tcf_idrinfo		*idrinfo;


	struct hlist_node		tcfa_head;
	u32				tcfa_index;
	u32				tcfa_index;
	int				tcfa_refcnt;
	int				tcfa_refcnt;
	int				tcfa_bindcnt;
	int				tcfa_bindcnt;
@@ -44,7 +40,6 @@ struct tc_action {
	struct tc_cookie	*act_cookie;
	struct tc_cookie	*act_cookie;
	struct tcf_chain	*goto_chain;
	struct tcf_chain	*goto_chain;
};
};
#define tcf_head	common.tcfa_head
#define tcf_index	common.tcfa_index
#define tcf_index	common.tcfa_index
#define tcf_refcnt	common.tcfa_refcnt
#define tcf_refcnt	common.tcfa_refcnt
#define tcf_bindcnt	common.tcfa_bindcnt
#define tcf_bindcnt	common.tcfa_bindcnt
@@ -57,27 +52,6 @@ struct tc_action {
#define tcf_lock	common.tcfa_lock
#define tcf_lock	common.tcfa_lock
#define tcf_rcu		common.tcfa_rcu
#define tcf_rcu		common.tcfa_rcu


static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
{
	return index & hmask;
}

static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
{
	int i;

	spin_lock_init(&hf->lock);
	hf->index = 0;
	hf->hmask = mask;
	hf->htab = kzalloc((mask + 1) * sizeof(struct hlist_head),
			   GFP_KERNEL);
	if (!hf->htab)
		return -ENOMEM;
	for (i = 0; i < mask + 1; i++)
		INIT_HLIST_HEAD(&hf->htab[i]);
	return 0;
}

/* Update lastuse only if needed, to avoid dirtying a cache line.
/* Update lastuse only if needed, to avoid dirtying a cache line.
 * We use a temp variable to avoid fetching jiffies twice.
 * We use a temp variable to avoid fetching jiffies twice.
 */
 */
@@ -126,53 +100,51 @@ struct tc_action_ops {
};
};


struct tc_action_net {
struct tc_action_net {
	struct tcf_hashinfo *hinfo;
	struct tcf_idrinfo *idrinfo;
	const struct tc_action_ops *ops;
	const struct tc_action_ops *ops;
};
};


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


	tn->hinfo = kmalloc(sizeof(*tn->hinfo), GFP_KERNEL);
	tn->idrinfo = kmalloc(sizeof(*tn->idrinfo), GFP_KERNEL);
	if (!tn->hinfo)
	if (!tn->idrinfo)
		return -ENOMEM;
		return -ENOMEM;
	tn->ops = ops;
	tn->ops = ops;
	err = tcf_hashinfo_init(tn->hinfo, mask);
	spin_lock_init(&tn->idrinfo->lock);
	if (err)
	idr_init(&tn->idrinfo->action_idr);
		kfree(tn->hinfo);
	return err;
	return err;
}
}


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


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


int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
		       struct netlink_callback *cb, int type,
		       const struct tc_action_ops *ops);
		       const struct tc_action_ops *ops);
int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
u32 tcf_hash_new_index(struct tc_action_net *tn);
bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
		    int bind);
		    int bind);
int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		    struct tc_action **a, const struct tc_action_ops *ops, int bind,
		   struct tc_action **a, const struct tc_action_ops *ops,
		    bool cpustats);
		   int bind, bool cpustats);
void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est);
void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a);
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);


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


static inline int tcf_hash_release(struct tc_action *a, bool bind)
static inline int tcf_idr_release(struct tc_action *a, bool bind)
{
{
	return __tcf_hash_release(a, bind, false);
	return __tcf_idr_release(a, bind, false);
}
}


int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
+121 −130
Original line number Original line Diff line number Diff line
@@ -70,11 +70,11 @@ static void free_tcf(struct rcu_head *head)
	kfree(p);
	kfree(p);
}
}


static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *p)
static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
{
{
	spin_lock_bh(&hinfo->lock);
	spin_lock_bh(&idrinfo->lock);
	hlist_del(&p->tcfa_head);
	idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
	spin_unlock_bh(&hinfo->lock);
	spin_unlock_bh(&idrinfo->lock);
	gen_kill_estimator(&p->tcfa_rate_est);
	gen_kill_estimator(&p->tcfa_rate_est);
	/*
	/*
	 * gen_estimator est_timer() might access p->tcfa_lock
	 * gen_estimator est_timer() might access p->tcfa_lock
@@ -83,7 +83,7 @@ static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *p)
	call_rcu(&p->tcfa_rcu, free_tcf);
	call_rcu(&p->tcfa_rcu, free_tcf);
}
}


int __tcf_hash_release(struct tc_action *p, bool bind, bool strict)
int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
{
{
	int ret = 0;
	int ret = 0;


@@ -97,34 +97,31 @@ int __tcf_hash_release(struct tc_action *p, bool bind, bool strict)
		if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) {
		if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) {
			if (p->ops->cleanup)
			if (p->ops->cleanup)
				p->ops->cleanup(p, bind);
				p->ops->cleanup(p, bind);
			tcf_hash_destroy(p->hinfo, p);
			tcf_idr_remove(p->idrinfo, p);
			ret = ACT_P_DELETED;
			ret = ACT_P_DELETED;
		}
		}
	}
	}


	return ret;
	return ret;
}
}
EXPORT_SYMBOL(__tcf_hash_release);
EXPORT_SYMBOL(__tcf_idr_release);


static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
			   struct netlink_callback *cb)
			   struct netlink_callback *cb)
{
{
	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
	int err = 0, index = -1, s_i = 0, n_i = 0;
	u32 act_flags = cb->args[2];
	u32 act_flags = cb->args[2];
	unsigned long jiffy_since = cb->args[3];
	unsigned long jiffy_since = cb->args[3];
	struct nlattr *nest;
	struct nlattr *nest;
	struct idr *idr = &idrinfo->action_idr;
	struct tc_action *p;
	unsigned long id = 1;


	spin_lock_bh(&hinfo->lock);
	spin_lock_bh(&idrinfo->lock);


	s_i = cb->args[0];
	s_i = cb->args[0];


	for (i = 0; i < (hinfo->hmask + 1); i++) {
	idr_for_each_entry_ext(idr, p, id) {
		struct hlist_head *head;
		struct tc_action *p;

		head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];

		hlist_for_each_entry_rcu(p, head, tcfa_head) {
		index++;
		index++;
		if (index < s_i)
		if (index < s_i)
			continue;
			continue;
@@ -135,7 +132,7 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
			continue;
			continue;


		nest = nla_nest_start(skb, n_i);
		nest = nla_nest_start(skb, n_i);
			if (nest == NULL)
		if (!nest)
			goto nla_put_failure;
			goto nla_put_failure;
		err = tcf_action_dump_1(skb, p, 0, 0);
		err = tcf_action_dump_1(skb, p, 0, 0);
		if (err < 0) {
		if (err < 0) {
@@ -149,12 +146,11 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
		    n_i >= TCA_ACT_MAX_PRIO)
		    n_i >= TCA_ACT_MAX_PRIO)
			goto done;
			goto done;
	}
	}
	}
done:
done:
	if (index >= 0)
	if (index >= 0)
		cb->args[0] = index + 1;
		cb->args[0] = index + 1;


	spin_unlock_bh(&hinfo->lock);
	spin_unlock_bh(&idrinfo->lock);
	if (n_i) {
	if (n_i) {
		if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
		if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
			cb->args[1] = n_i;
			cb->args[1] = n_i;
@@ -166,30 +162,28 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
	goto done;
	goto done;
}
}


static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
			  const struct tc_action_ops *ops)
			  const struct tc_action_ops *ops)
{
{
	struct nlattr *nest;
	struct nlattr *nest;
	int i = 0, n_i = 0;
	int n_i = 0;
	int ret = -EINVAL;
	int ret = -EINVAL;
	struct idr *idr = &idrinfo->action_idr;
	struct tc_action *p;
	unsigned long id = 1;


	nest = nla_nest_start(skb, 0);
	nest = nla_nest_start(skb, 0);
	if (nest == NULL)
	if (nest == NULL)
		goto nla_put_failure;
		goto nla_put_failure;
	if (nla_put_string(skb, TCA_KIND, ops->kind))
	if (nla_put_string(skb, TCA_KIND, ops->kind))
		goto nla_put_failure;
		goto nla_put_failure;
	for (i = 0; i < (hinfo->hmask + 1); i++) {
		struct hlist_head *head;
		struct hlist_node *n;
		struct tc_action *p;


		head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
	idr_for_each_entry_ext(idr, p, id) {
		hlist_for_each_entry_safe(p, n, head, tcfa_head) {
		ret = __tcf_idr_release(p, false, true);
			ret = __tcf_hash_release(p, false, true);
		if (ret == ACT_P_DELETED) {
		if (ret == ACT_P_DELETED) {
			module_put(p->ops->owner);
			module_put(p->ops->owner);
			n_i++;
			n_i++;
			} else if (ret < 0)
		} else if (ret < 0) {
			goto nla_put_failure;
			goto nla_put_failure;
		}
		}
	}
	}
@@ -207,12 +201,12 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
		       struct netlink_callback *cb, int type,
		       const struct tc_action_ops *ops)
		       const struct tc_action_ops *ops)
{
{
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_idrinfo *idrinfo = tn->idrinfo;


	if (type == RTM_DELACTION) {
	if (type == RTM_DELACTION) {
		return tcf_del_walker(hinfo, skb, ops);
		return tcf_del_walker(idrinfo, skb, ops);
	} else if (type == RTM_GETACTION) {
	} else if (type == RTM_GETACTION) {
		return tcf_dump_walker(hinfo, skb, cb);
		return tcf_dump_walker(idrinfo, skb, cb);
	} else {
	} else {
		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
		return -EINVAL;
		return -EINVAL;
@@ -220,40 +214,21 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
}
}
EXPORT_SYMBOL(tcf_generic_walker);
EXPORT_SYMBOL(tcf_generic_walker);


static struct tc_action *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
static struct tc_action *tcf_idr_lookup(u32 index, struct tcf_idrinfo *idrinfo)
{
{
	struct tc_action *p = NULL;
	struct tc_action *p = NULL;
	struct hlist_head *head;


	spin_lock_bh(&hinfo->lock);
	spin_lock_bh(&idrinfo->lock);
	head = &hinfo->htab[tcf_hash(index, hinfo->hmask)];
	p = idr_find_ext(&idrinfo->action_idr, index);
	hlist_for_each_entry_rcu(p, head, tcfa_head)
	spin_unlock_bh(&idrinfo->lock);
		if (p->tcfa_index == index)
			break;
	spin_unlock_bh(&hinfo->lock);


	return p;
	return p;
}
}


u32 tcf_hash_new_index(struct tc_action_net *tn)
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
{
	struct tcf_hashinfo *hinfo = tn->hinfo;
	u32 val = hinfo->index;

	do {
		if (++val == 0)
			val = 1;
	} while (tcf_hash_lookup(val, hinfo));

	hinfo->index = val;
	return val;
}
EXPORT_SYMBOL(tcf_hash_new_index);

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


	if (p) {
	if (p) {
		*a = p;
		*a = p;
@@ -261,15 +236,15 @@ int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
	}
	}
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(tcf_hash_search);
EXPORT_SYMBOL(tcf_idr_search);


bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
		   int bind)
		   int bind)
{
{
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	struct tc_action *p = NULL;
	struct tc_action *p = tcf_idr_lookup(index, idrinfo);


	if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
	if (index && p) {
		if (bind)
		if (bind)
			p->tcfa_bindcnt++;
			p->tcfa_bindcnt++;
		p->tcfa_refcnt++;
		p->tcfa_refcnt++;
@@ -278,23 +253,25 @@ bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
	}
	}
	return false;
	return false;
}
}
EXPORT_SYMBOL(tcf_hash_check);
EXPORT_SYMBOL(tcf_idr_check);


void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est)
{
{
	if (est)
	if (est)
		gen_kill_estimator(&a->tcfa_rate_est);
		gen_kill_estimator(&a->tcfa_rate_est);
	call_rcu(&a->tcfa_rcu, free_tcf);
	call_rcu(&a->tcfa_rcu, free_tcf);
}
}
EXPORT_SYMBOL(tcf_hash_cleanup);
EXPORT_SYMBOL(tcf_idr_cleanup);


int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		   struct tc_action **a, const struct tc_action_ops *ops,
		   struct tc_action **a, const struct tc_action_ops *ops,
		   int bind, bool cpustats)
		   int bind, bool cpustats)
{
{
	struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
	struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	struct idr *idr = &idrinfo->action_idr;
	int err = -ENOMEM;
	int err = -ENOMEM;
	unsigned long idr_index;


	if (unlikely(!p))
	if (unlikely(!p))
		return -ENOMEM;
		return -ENOMEM;
@@ -317,8 +294,28 @@ int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		}
		}
	}
	}
	spin_lock_init(&p->tcfa_lock);
	spin_lock_init(&p->tcfa_lock);
	INIT_HLIST_NODE(&p->tcfa_head);
	/* user doesn't specify an index */
	p->tcfa_index = index ? index : tcf_hash_new_index(tn);
	if (!index) {
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, &idr_index, 1, 0,
				    GFP_KERNEL);
		spin_unlock_bh(&idrinfo->lock);
		if (err) {
err3:
			free_percpu(p->cpu_qstats);
			goto err2;
		}
		p->tcfa_index = idr_index;
	} else {
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, NULL, index, index + 1,
				    GFP_KERNEL);
		spin_unlock_bh(&idrinfo->lock);
		if (err)
			goto err3;
		p->tcfa_index = index;
	}

	p->tcfa_tm.install = jiffies;
	p->tcfa_tm.install = jiffies;
	p->tcfa_tm.lastuse = jiffies;
	p->tcfa_tm.lastuse = jiffies;
	p->tcfa_tm.firstuse = 0;
	p->tcfa_tm.firstuse = 0;
@@ -327,52 +324,46 @@ int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
					&p->tcfa_rate_est,
					&p->tcfa_rate_est,
					&p->tcfa_lock, NULL, est);
					&p->tcfa_lock, NULL, est);
		if (err) {
		if (err) {
			free_percpu(p->cpu_qstats);
			goto err3;
			goto err2;
		}
		}
	}
	}


	p->hinfo = hinfo;
	p->idrinfo = idrinfo;
	p->ops = ops;
	p->ops = ops;
	INIT_LIST_HEAD(&p->list);
	INIT_LIST_HEAD(&p->list);
	*a = p;
	*a = p;
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(tcf_hash_create);
EXPORT_SYMBOL(tcf_idr_create);


void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a)
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
{
{
	struct tcf_hashinfo *hinfo = tn->hinfo;
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	unsigned int h = tcf_hash(a->tcfa_index, hinfo->hmask);


	spin_lock_bh(&hinfo->lock);
	spin_lock_bh(&idrinfo->lock);
	hlist_add_head(&a->tcfa_head, &hinfo->htab[h]);
	idr_replace_ext(&idrinfo->action_idr, a, a->tcfa_index);
	spin_unlock_bh(&hinfo->lock);
	spin_unlock_bh(&idrinfo->lock);
}
}
EXPORT_SYMBOL(tcf_hash_insert);
EXPORT_SYMBOL(tcf_idr_insert);


void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
			  struct tcf_hashinfo *hinfo)
			 struct tcf_idrinfo *idrinfo)
{
{
	int i;
	struct idr *idr = &idrinfo->action_idr;

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

		hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfa_head) {
	int ret;
	int ret;
	unsigned long id = 1;


			ret = __tcf_hash_release(p, false, true);
	idr_for_each_entry_ext(idr, p, id) {
		ret = __tcf_idr_release(p, false, true);
		if (ret == ACT_P_DELETED)
		if (ret == ACT_P_DELETED)
			module_put(ops->owner);
			module_put(ops->owner);
		else if (ret < 0)
		else if (ret < 0)
			return;
			return;
	}
	}
	idr_destroy(&idrinfo->action_idr);
}
}
	kfree(hinfo->htab);
EXPORT_SYMBOL(tcf_idrinfo_destroy);
}
EXPORT_SYMBOL(tcf_hashinfo_destroy);


static LIST_HEAD(act_base);
static LIST_HEAD(act_base);
static DEFINE_RWLOCK(act_mod_lock);
static DEFINE_RWLOCK(act_mod_lock);
@@ -524,7 +515,7 @@ int tcf_action_destroy(struct list_head *actions, int bind)
	int ret = 0;
	int ret = 0;


	list_for_each_entry_safe(a, tmp, actions, list) {
	list_for_each_entry_safe(a, tmp, actions, list) {
		ret = __tcf_hash_release(a, bind, true);
		ret = __tcf_idr_release(a, bind, true);
		if (ret == ACT_P_DELETED)
		if (ret == ACT_P_DELETED)
			module_put(a->ops->owner);
			module_put(a->ops->owner);
		else if (ret < 0)
		else if (ret < 0)
+8 −9
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@
#include <linux/tc_act/tc_bpf.h>
#include <linux/tc_act/tc_bpf.h>
#include <net/tc_act/tc_bpf.h>
#include <net/tc_act/tc_bpf.h>


#define BPF_TAB_MASK		15
#define ACT_BPF_NAME_LEN	256
#define ACT_BPF_NAME_LEN	256


struct tcf_bpf_cfg {
struct tcf_bpf_cfg {
@@ -295,8 +294,8 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,


	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);


	if (!tcf_hash_check(tn, parm->index, act, bind)) {
	if (!tcf_idr_check(tn, parm->index, act, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, act,
		ret = tcf_idr_create(tn, parm->index, est, act,
				     &act_bpf_ops, bind, true);
				     &act_bpf_ops, bind, true);
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
@@ -307,7 +306,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
		if (bind)
		if (bind)
			return 0;
			return 0;


		tcf_hash_release(*act, bind);
		tcf_idr_release(*act, bind);
		if (!replace)
		if (!replace)
			return -EEXIST;
			return -EEXIST;
	}
	}
@@ -343,7 +342,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
	rcu_assign_pointer(prog->filter, cfg.filter);
	rcu_assign_pointer(prog->filter, cfg.filter);


	if (res == ACT_P_CREATED) {
	if (res == ACT_P_CREATED) {
		tcf_hash_insert(tn, *act);
		tcf_idr_insert(tn, *act);
	} else {
	} else {
		/* make sure the program being replaced is no longer executing */
		/* make sure the program being replaced is no longer executing */
		synchronize_rcu();
		synchronize_rcu();
@@ -353,7 +352,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
	return res;
	return res;
out:
out:
	if (res == ACT_P_CREATED)
	if (res == ACT_P_CREATED)
		tcf_hash_cleanup(*act, est);
		tcf_idr_cleanup(*act, est);


	return ret;
	return ret;
}
}
@@ -379,7 +378,7 @@ 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);
	struct tc_action_net *tn = net_generic(net, bpf_net_id);


	return tcf_hash_search(tn, a, index);
	return tcf_idr_search(tn, a, index);
}
}


static struct tc_action_ops act_bpf_ops __read_mostly = {
static struct tc_action_ops act_bpf_ops __read_mostly = {
@@ -399,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
{
{
	struct tc_action_net *tn = net_generic(net, bpf_net_id);
	struct tc_action_net *tn = net_generic(net, bpf_net_id);


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


static void __net_exit bpf_exit_net(struct net *net)
static void __net_exit bpf_exit_net(struct net *net)
+7 −9
Original line number Original line Diff line number Diff line
@@ -28,8 +28,6 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_zones.h>


#define CONNMARK_TAB_MASK     3

static unsigned int connmark_net_id;
static unsigned int connmark_net_id;
static struct tc_action_ops act_connmark_ops;
static struct tc_action_ops act_connmark_ops;


@@ -119,8 +117,8 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,


	parm = nla_data(tb[TCA_CONNMARK_PARMS]);
	parm = nla_data(tb[TCA_CONNMARK_PARMS]);


	if (!tcf_hash_check(tn, parm->index, a, bind)) {
	if (!tcf_idr_check(tn, parm->index, a, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, a,
		ret = tcf_idr_create(tn, parm->index, est, a,
				     &act_connmark_ops, bind, false);
				     &act_connmark_ops, bind, false);
		if (ret)
		if (ret)
			return ret;
			return ret;
@@ -130,13 +128,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
		ci->net = net;
		ci->net = net;
		ci->zone = parm->zone;
		ci->zone = parm->zone;


		tcf_hash_insert(tn, *a);
		tcf_idr_insert(tn, *a);
		ret = ACT_P_CREATED;
		ret = ACT_P_CREATED;
	} else {
	} else {
		ci = to_connmark(*a);
		ci = to_connmark(*a);
		if (bind)
		if (bind)
			return 0;
			return 0;
		tcf_hash_release(*a, bind);
		tcf_idr_release(*a, bind);
		if (!ovr)
		if (!ovr)
			return -EEXIST;
			return -EEXIST;
		/* replacing action and zone */
		/* replacing action and zone */
@@ -189,7 +187,7 @@ 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);
	struct tc_action_net *tn = net_generic(net, connmark_net_id);


	return tcf_hash_search(tn, a, index);
	return tcf_idr_search(tn, a, index);
}
}


static struct tc_action_ops act_connmark_ops = {
static struct tc_action_ops act_connmark_ops = {
@@ -208,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
{
{
	struct tc_action_net *tn = net_generic(net, connmark_net_id);
	struct tc_action_net *tn = net_generic(net, connmark_net_id);


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


static void __net_exit connmark_exit_net(struct net *net)
static void __net_exit connmark_exit_net(struct net *net)
+7 −9
Original line number Original line Diff line number Diff line
@@ -37,8 +37,6 @@
#include <linux/tc_act/tc_csum.h>
#include <linux/tc_act/tc_csum.h>
#include <net/tc_act/tc_csum.h>
#include <net/tc_act/tc_csum.h>


#define CSUM_TAB_MASK 15

static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
	[TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
	[TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
};
};
@@ -67,8 +65,8 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
		return -EINVAL;
		return -EINVAL;
	parm = nla_data(tb[TCA_CSUM_PARMS]);
	parm = nla_data(tb[TCA_CSUM_PARMS]);


	if (!tcf_hash_check(tn, parm->index, a, bind)) {
	if (!tcf_idr_check(tn, parm->index, a, bind)) {
		ret = tcf_hash_create(tn, parm->index, est, a,
		ret = tcf_idr_create(tn, parm->index, est, a,
				     &act_csum_ops, bind, false);
				     &act_csum_ops, bind, false);
		if (ret)
		if (ret)
			return ret;
			return ret;
@@ -76,7 +74,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
	} else {
	} else {
		if (bind)/* dont override defaults */
		if (bind)/* dont override defaults */
			return 0;
			return 0;
		tcf_hash_release(*a, bind);
		tcf_idr_release(*a, bind);
		if (!ovr)
		if (!ovr)
			return -EEXIST;
			return -EEXIST;
	}
	}
@@ -88,7 +86,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
	spin_unlock_bh(&p->tcf_lock);
	spin_unlock_bh(&p->tcf_lock);


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


	return ret;
	return ret;
}
}
@@ -609,7 +607,7 @@ 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);
	struct tc_action_net *tn = net_generic(net, csum_net_id);


	return tcf_hash_search(tn, a, index);
	return tcf_idr_search(tn, a, index);
}
}


static struct tc_action_ops act_csum_ops = {
static struct tc_action_ops act_csum_ops = {
@@ -628,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
{
{
	struct tc_action_net *tn = net_generic(net, csum_net_id);
	struct tc_action_net *tn = net_generic(net, csum_net_id);


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


static void __net_exit csum_exit_net(struct net *net)
static void __net_exit csum_exit_net(struct net *net)
Loading