Commit f379fdf1 authored by David S. Miller's avatar David S. Miller

Merge branch 'net_sched-idr'

Chris Mi says:

====================
net/sched: Improve getting objects by indexes

Using current TC code, it is very slow to insert a lot of rules.

In order to improve the rules update rate in TC,
we introduced the following two changes:
        1) changed cls_flower to use IDR to manage the filters.
        2) changed all act_xxx modules to use IDR instead of
           a small hash table

But IDR has a limitation that it uses int. TC handle uses u32.
To make sure there is no regression, we add several new IDR APIs
to support unsigned long.

v2
==

Addressed Hannes's comment:
express idr_alloc in terms of idr_alloc_ext and most of the other functions
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c2f8a6ce 65a206c0
...@@ -80,19 +80,75 @@ static inline void idr_set_cursor(struct idr *idr, unsigned int val) ...@@ -80,19 +80,75 @@ static inline void idr_set_cursor(struct idr *idr, unsigned int val)
*/ */
void idr_preload(gfp_t gfp_mask); void idr_preload(gfp_t gfp_mask);
int idr_alloc(struct idr *, void *entry, int start, int end, gfp_t);
int idr_alloc_cmn(struct idr *idr, void *ptr, unsigned long *index,
unsigned long start, unsigned long end, gfp_t gfp,
bool ext);
/**
* idr_alloc - allocate an id
* @idr: idr handle
* @ptr: pointer to be associated with the new id
* @start: the minimum id (inclusive)
* @end: the maximum id (exclusive)
* @gfp: memory allocation flags
*
* Allocates an unused ID in the range [start, end). Returns -ENOSPC
* if there are no unused IDs in that range.
*
* Note that @end is treated as max when <= 0. This is to always allow
* using @start + N as @end as long as N is inside integer range.
*
* Simultaneous modifications to the @idr are not allowed and should be
* prevented by the user, usually with a lock. idr_alloc() may be called
* concurrently with read-only accesses to the @idr, such as idr_find() and
* idr_for_each_entry().
*/
static inline int idr_alloc(struct idr *idr, void *ptr,
int start, int end, gfp_t gfp)
{
unsigned long id;
int ret;
if (WARN_ON_ONCE(start < 0))
return -EINVAL;
ret = idr_alloc_cmn(idr, ptr, &id, start, end, gfp, false);
if (ret)
return ret;
return id;
}
static inline int idr_alloc_ext(struct idr *idr, void *ptr,
unsigned long *index,
unsigned long start,
unsigned long end,
gfp_t gfp)
{
return idr_alloc_cmn(idr, ptr, index, start, end, gfp, true);
}
int idr_alloc_cyclic(struct idr *, void *entry, int start, int end, gfp_t); int idr_alloc_cyclic(struct idr *, void *entry, int start, int end, gfp_t);
int idr_for_each(const struct idr *, int idr_for_each(const struct idr *,
int (*fn)(int id, void *p, void *data), void *data); int (*fn)(int id, void *p, void *data), void *data);
void *idr_get_next(struct idr *, int *nextid); void *idr_get_next(struct idr *, int *nextid);
void *idr_get_next_ext(struct idr *idr, unsigned long *nextid);
void *idr_replace(struct idr *, void *, int id); void *idr_replace(struct idr *, void *, int id);
void *idr_replace_ext(struct idr *idr, void *ptr, unsigned long id);
void idr_destroy(struct idr *); void idr_destroy(struct idr *);
static inline void *idr_remove(struct idr *idr, int id) static inline void *idr_remove_ext(struct idr *idr, unsigned long id)
{ {
return radix_tree_delete_item(&idr->idr_rt, id, NULL); return radix_tree_delete_item(&idr->idr_rt, id, NULL);
} }
static inline void *idr_remove(struct idr *idr, int id)
{
return idr_remove_ext(idr, id);
}
static inline void idr_init(struct idr *idr) static inline void idr_init(struct idr *idr)
{ {
INIT_RADIX_TREE(&idr->idr_rt, IDR_RT_MARKER); INIT_RADIX_TREE(&idr->idr_rt, IDR_RT_MARKER);
...@@ -128,11 +184,16 @@ static inline void idr_preload_end(void) ...@@ -128,11 +184,16 @@ static inline void idr_preload_end(void)
* This function can be called under rcu_read_lock(), given that the leaf * This function can be called under rcu_read_lock(), given that the leaf
* pointers lifetimes are correctly managed. * pointers lifetimes are correctly managed.
*/ */
static inline void *idr_find(const struct idr *idr, int id) static inline void *idr_find_ext(const struct idr *idr, unsigned long id)
{ {
return radix_tree_lookup(&idr->idr_rt, id); return radix_tree_lookup(&idr->idr_rt, id);
} }
static inline void *idr_find(const struct idr *idr, int id)
{
return idr_find_ext(idr, id);
}
/** /**
* idr_for_each_entry - iterate over an idr's elements of a given type * idr_for_each_entry - iterate over an idr's elements of a given type
* @idr: idr handle * @idr: idr handle
...@@ -145,6 +206,8 @@ static inline void *idr_find(const struct idr *idr, int id) ...@@ -145,6 +206,8 @@ static inline void *idr_find(const struct idr *idr, int id)
*/ */
#define idr_for_each_entry(idr, entry, id) \ #define idr_for_each_entry(idr, entry, id) \
for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; ++id) for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; ++id)
#define idr_for_each_entry_ext(idr, entry, id) \
for (id = 0; ((entry) = idr_get_next_ext(idr, &(id))) != NULL; ++id)
/** /**
* idr_for_each_entry_continue - continue iteration over an idr's elements of a given type * idr_for_each_entry_continue - continue iteration over an idr's elements of a given type
......
...@@ -357,8 +357,25 @@ int radix_tree_split(struct radix_tree_root *, unsigned long index, ...@@ -357,8 +357,25 @@ int radix_tree_split(struct radix_tree_root *, unsigned long index,
unsigned new_order); unsigned new_order);
int radix_tree_join(struct radix_tree_root *, unsigned long index, int radix_tree_join(struct radix_tree_root *, unsigned long index,
unsigned new_order, void *); unsigned new_order, void *);
void __rcu **idr_get_free(struct radix_tree_root *, struct radix_tree_iter *,
gfp_t, int end); void __rcu **idr_get_free_cmn(struct radix_tree_root *root,
struct radix_tree_iter *iter, gfp_t gfp,
unsigned long max);
static inline void __rcu **idr_get_free(struct radix_tree_root *root,
struct radix_tree_iter *iter,
gfp_t gfp,
int end)
{
return idr_get_free_cmn(root, iter, gfp, end > 0 ? end - 1 : INT_MAX);
}
static inline void __rcu **idr_get_free_ext(struct radix_tree_root *root,
struct radix_tree_iter *iter,
gfp_t gfp,
unsigned long end)
{
return idr_get_free_cmn(root, iter, gfp, end - 1);
}
enum { enum {
RADIX_TREE_ITER_TAG_MASK = 0x0f, /* tag index in lower nybble */ RADIX_TREE_ITER_TAG_MASK = 0x0f, /* tag index in lower nybble */
......
...@@ -10,12 +10,9 @@ ...@@ -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 { spinlock_t lock;
struct hlist_head *htab; struct idr action_idr;
unsigned int hmask;
spinlock_t lock;
u32 index;
}; };
struct tc_action_ops; struct tc_action_ops;
...@@ -25,9 +22,8 @@ struct tc_action { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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);
......
...@@ -7,45 +7,32 @@ ...@@ -7,45 +7,32 @@
DEFINE_PER_CPU(struct ida_bitmap *, ida_bitmap); DEFINE_PER_CPU(struct ida_bitmap *, ida_bitmap);
static DEFINE_SPINLOCK(simple_ida_lock); static DEFINE_SPINLOCK(simple_ida_lock);
/** int idr_alloc_cmn(struct idr *idr, void *ptr, unsigned long *index,
* idr_alloc - allocate an id unsigned long start, unsigned long end, gfp_t gfp,
* @idr: idr handle bool ext)
* @ptr: pointer to be associated with the new id
* @start: the minimum id (inclusive)
* @end: the maximum id (exclusive)
* @gfp: memory allocation flags
*
* Allocates an unused ID in the range [start, end). Returns -ENOSPC
* if there are no unused IDs in that range.
*
* Note that @end is treated as max when <= 0. This is to always allow
* using @start + N as @end as long as N is inside integer range.
*
* Simultaneous modifications to the @idr are not allowed and should be
* prevented by the user, usually with a lock. idr_alloc() may be called
* concurrently with read-only accesses to the @idr, such as idr_find() and
* idr_for_each_entry().
*/
int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
{ {
void __rcu **slot;
struct radix_tree_iter iter; struct radix_tree_iter iter;
void __rcu **slot;
if (WARN_ON_ONCE(start < 0))
return -EINVAL;
if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
return -EINVAL; return -EINVAL;
radix_tree_iter_init(&iter, start); radix_tree_iter_init(&iter, start);
slot = idr_get_free(&idr->idr_rt, &iter, gfp, end); if (ext)
slot = idr_get_free_ext(&idr->idr_rt, &iter, gfp, end);
else
slot = idr_get_free(&idr->idr_rt, &iter, gfp, end);
if (IS_ERR(slot)) if (IS_ERR(slot))
return PTR_ERR(slot); return PTR_ERR(slot);
radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr); radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr);
radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE); radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE);
return iter.index;
if (index)
*index = iter.index;
return 0;
} }
EXPORT_SYMBOL_GPL(idr_alloc); EXPORT_SYMBOL_GPL(idr_alloc_cmn);
/** /**
* idr_alloc_cyclic - allocate new idr entry in a cyclical fashion * idr_alloc_cyclic - allocate new idr entry in a cyclical fashion
...@@ -134,6 +121,20 @@ void *idr_get_next(struct idr *idr, int *nextid) ...@@ -134,6 +121,20 @@ void *idr_get_next(struct idr *idr, int *nextid)
} }
EXPORT_SYMBOL(idr_get_next); EXPORT_SYMBOL(idr_get_next);
void *idr_get_next_ext(struct idr *idr, unsigned long *nextid)
{
struct radix_tree_iter iter;
void __rcu **slot;
slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid);
if (!slot)
return NULL;
*nextid = iter.index;
return rcu_dereference_raw(*slot);
}
EXPORT_SYMBOL(idr_get_next_ext);
/** /**
* idr_replace - replace pointer for given id * idr_replace - replace pointer for given id
* @idr: idr handle * @idr: idr handle
...@@ -149,13 +150,20 @@ EXPORT_SYMBOL(idr_get_next); ...@@ -149,13 +150,20 @@ EXPORT_SYMBOL(idr_get_next);
* %-EINVAL indicates that @id or @ptr were not valid. * %-EINVAL indicates that @id or @ptr were not valid.
*/ */
void *idr_replace(struct idr *idr, void *ptr, int id) void *idr_replace(struct idr *idr, void *ptr, int id)
{
if (WARN_ON_ONCE(id < 0))
return ERR_PTR(-EINVAL);
return idr_replace_ext(idr, ptr, id);
}
EXPORT_SYMBOL(idr_replace);
void *idr_replace_ext(struct idr *idr, void *ptr, unsigned long id)
{ {
struct radix_tree_node *node; struct radix_tree_node *node;
void __rcu **slot = NULL; void __rcu **slot = NULL;
void *entry; void *entry;
if (WARN_ON_ONCE(id < 0))
return ERR_PTR(-EINVAL);
if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -167,7 +175,7 @@ void *idr_replace(struct idr *idr, void *ptr, int id) ...@@ -167,7 +175,7 @@ void *idr_replace(struct idr *idr, void *ptr, int id)
return entry; return entry;
} }
EXPORT_SYMBOL(idr_replace); EXPORT_SYMBOL(idr_replace_ext);
/** /**
* DOC: IDA description * DOC: IDA description
......
...@@ -2137,13 +2137,13 @@ int ida_pre_get(struct ida *ida, gfp_t gfp) ...@@ -2137,13 +2137,13 @@ int ida_pre_get(struct ida *ida, gfp_t gfp)
} }
EXPORT_SYMBOL(ida_pre_get); EXPORT_SYMBOL(ida_pre_get);
void __rcu **idr_get_free(struct radix_tree_root *root, void __rcu **idr_get_free_cmn(struct radix_tree_root *root,
struct radix_tree_iter *iter, gfp_t gfp, int end) struct radix_tree_iter *iter, gfp_t gfp,
unsigned long max)
{ {
struct radix_tree_node *node = NULL, *child; struct radix_tree_node *node = NULL, *child;
void __rcu **slot = (void __rcu **)&root->rnode; void __rcu **slot = (void __rcu **)&root->rnode;
unsigned long maxindex, start = iter->next_index; unsigned long maxindex, start = iter->next_index;
unsigned long max = end > 0 ? end - 1 : INT_MAX;
unsigned int shift, offset = 0; unsigned int shift, offset = 0;
grow: grow:
......
...@@ -70,11 +70,11 @@ static void free_tcf(struct rcu_head *head) ...@@ -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) ...@@ -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,64 +97,60 @@ int __tcf_hash_release(struct tc_action *p, bool bind, bool strict) ...@@ -97,64 +97,60 @@ 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; index++;
struct tc_action *p; if (index < s_i)
continue;
head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
if (jiffy_since &&
hlist_for_each_entry_rcu(p, head, tcfa_head) { time_after(jiffy_since,
index++; (unsigned long)p->tcfa_tm.lastuse))
if (index < s_i) continue;
continue;
nest = nla_nest_start(skb, n_i);
if (jiffy_since && if (!nest)
time_after(jiffy_since, goto nla_put_failure;
(unsigned long)p->tcfa_tm.lastuse)) err = tcf_action_dump_1(skb, p, 0, 0);
continue; if (err < 0) {
index--;
nest = nla_nest_start(skb, n_i); nlmsg_trim(skb, nest);
if (nest == NULL) goto done;
goto nla_put_failure;
err = tcf_action_dump_1(skb, p, 0, 0);
if (err < 0) {
index--;
nlmsg_trim(skb, nest);
goto done;
}
nla_nest_end(skb, nest);
n_i++;
if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
n_i >= TCA_ACT_MAX_PRIO)
goto done;
} }
nla_nest_end(skb, nest);
n_i++;
if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
n_i >= TCA_ACT_MAX_PRIO)
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,31 +162,29 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, ...@@ -166,31 +162,29 @@ 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; idr_for_each_entry_ext(idr, p, id) {
struct hlist_node *n; ret = __tcf_idr_release(p, false, true);
struct tc_action *p; if (ret == ACT_P_DELETED) {
module_put(p->ops->owner);
head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; n_i++;
hlist_for_each_entry_safe(p, n, head, tcfa_head) { } else if (ret < 0) {
ret = __tcf_hash_release(p, false, true); goto nla_put_failure;
if (ret == ACT_P_DELETED) {
module_put(p->ops->owner);
n_i++;
} else if (ret < 0)
goto nla_put_failure;
} }
} }
if (nla_put_u32(skb, TCA_FCNT, n_i)) if (nla_put_u32(skb, TCA_FCNT, n_i))
...@@ -207,12 +201,12 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
struct tc_action *p;
for (i = 0; i < hinfo->hmask + 1; i++) { int ret;
struct tc_action *p; unsigned long id = 1;
struct hlist_node *n;
hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfa_head) {
int ret;
ret = __tcf_hash_release(p, false, true); idr_for_each_entry_ext(idr, p, id) {
if (ret == ACT_P_DELETED) ret = __tcf_idr_release(p, false, true);
module_put(ops->owner); if (ret == ACT_P_DELETED)
else if (ret < 0) module_put(ops->owner);
return; else if (ret < 0)
} return;
} }
kfree(hinfo->htab); idr_destroy(&idrinfo->action_idr);
} }
EXPORT_SYMBOL(tcf_hashinfo_destroy); EXPORT_SYMBOL(tcf_idrinfo_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) ...@@ -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)
......
...@@ -21,7 +21,6 @@ ...@@ -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,9 +294,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, ...@@ -295,9 +294,9 @@ 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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -28,8 +28,6 @@ ...@@ -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,9 +117,9 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, ...@@ -119,9 +117,9 @@ 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, ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -37,8 +37,6 @@ ...@@ -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,16 +65,16 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, ...@@ -67,16 +65,16 @@ 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;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} 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, ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include <linux/tc_act/tc_gact.h> #include <linux/tc_act/tc_gact.h>
#include <net/tc_act/tc_gact.h> #include <net/tc_act/tc_gact.h>
#define GACT_TAB_MASK 15
static unsigned int gact_net_id; static unsigned int gact_net_id;
static struct tc_action_ops act_gact_ops; static struct tc_action_ops act_gact_ops;
...@@ -92,16 +90,16 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, ...@@ -92,16 +90,16 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
} }
#endif #endif
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_gact_ops, bind, true); &act_gact_ops, bind, true);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} 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;
} }
...@@ -122,7 +120,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, ...@@ -122,7 +120,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
} }
#endif #endif
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
} }
...@@ -214,7 +212,7 @@ static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index) ...@@ -214,7 +212,7 @@ static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, gact_net_id); struct tc_action_net *tn = net_generic(net, gact_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_gact_ops = { static struct tc_action_ops act_gact_ops = {
...@@ -234,7 +232,7 @@ static __net_init int gact_init_net(struct net *net) ...@@ -234,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, gact_net_id); struct tc_action_net *tn = net_generic(net, gact_net_id);
return tc_action_net_init(tn, &act_gact_ops, GACT_TAB_MASK); return tc_action_net_init(tn, &act_gact_ops);
} }
static void __net_exit gact_exit_net(struct net *net) static void __net_exit gact_exit_net(struct net *net)
......
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/ife.h> #include <net/ife.h>
#define IFE_TAB_MASK 15
static unsigned int ife_net_id; static unsigned int ife_net_id;
static int max_metacnt = IFE_META_MAX + 1; static int max_metacnt = IFE_META_MAX + 1;
static struct tc_action_ops act_ife_ops; static struct tc_action_ops act_ife_ops;
...@@ -452,18 +450,18 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -452,18 +450,18 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_IFE_PARMS]); parm = nla_data(tb[TCA_IFE_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, &act_ife_ops, ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
bind, false); bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -507,7 +505,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -507,7 +505,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (err) { if (err) {
metadata_parse_err: metadata_parse_err:
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
_tcf_ife_cleanup(*a, bind); _tcf_ife_cleanup(*a, bind);
...@@ -541,7 +539,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -541,7 +539,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&ife->tcf_lock); spin_unlock_bh(&ife->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;
} }
...@@ -800,7 +798,7 @@ static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index) ...@@ -800,7 +798,7 @@ static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, ife_net_id); struct tc_action_net *tn = net_generic(net, ife_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_ife_ops = { static struct tc_action_ops act_ife_ops = {
...@@ -820,7 +818,7 @@ static __net_init int ife_init_net(struct net *net) ...@@ -820,7 +818,7 @@ static __net_init int ife_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ife_net_id); struct tc_action_net *tn = net_generic(net, ife_net_id);
return tc_action_net_init(tn, &act_ife_ops, IFE_TAB_MASK); return tc_action_net_init(tn, &act_ife_ops);
} }
static void __net_exit ife_exit_net(struct net *net) static void __net_exit ife_exit_net(struct net *net)
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#define IPT_TAB_MASK 15
static unsigned int ipt_net_id; static unsigned int ipt_net_id;
static struct tc_action_ops act_ipt_ops; static struct tc_action_ops act_ipt_ops;
...@@ -118,33 +116,33 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, ...@@ -118,33 +116,33 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
if (tb[TCA_IPT_INDEX] != NULL) if (tb[TCA_IPT_INDEX] != NULL)
index = nla_get_u32(tb[TCA_IPT_INDEX]); index = nla_get_u32(tb[TCA_IPT_INDEX]);
exists = tcf_hash_check(tn, index, a, bind); exists = tcf_idr_check(tn, index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) { if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) { if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, index, est, a, ops, bind, ret = tcf_idr_create(tn, index, est, a, ops, bind,
false); false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} 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;
...@@ -180,7 +178,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, ...@@ -180,7 +178,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
ipt->tcfi_hook = hook; ipt->tcfi_hook = hook;
spin_unlock_bh(&ipt->tcf_lock); spin_unlock_bh(&ipt->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;
err3: err3:
...@@ -189,7 +187,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, ...@@ -189,7 +187,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
kfree(tname); kfree(tname);
err1: err1:
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_cleanup(*a, est); tcf_idr_cleanup(*a, est);
return err; return err;
} }
...@@ -316,7 +314,7 @@ static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index) ...@@ -316,7 +314,7 @@ static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, ipt_net_id); struct tc_action_net *tn = net_generic(net, ipt_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_ipt_ops = { static struct tc_action_ops act_ipt_ops = {
...@@ -336,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net) ...@@ -336,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ipt_net_id); struct tc_action_net *tn = net_generic(net, ipt_net_id);
return tc_action_net_init(tn, &act_ipt_ops, IPT_TAB_MASK); return tc_action_net_init(tn, &act_ipt_ops);
} }
static void __net_exit ipt_exit_net(struct net *net) static void __net_exit ipt_exit_net(struct net *net)
...@@ -366,7 +364,7 @@ static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index) ...@@ -366,7 +364,7 @@ static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, xt_net_id); struct tc_action_net *tn = net_generic(net, xt_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_xt_ops = { static struct tc_action_ops act_xt_ops = {
...@@ -386,7 +384,7 @@ static __net_init int xt_init_net(struct net *net) ...@@ -386,7 +384,7 @@ static __net_init int xt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, xt_net_id); struct tc_action_net *tn = net_generic(net, xt_net_id);
return tc_action_net_init(tn, &act_xt_ops, IPT_TAB_MASK); return tc_action_net_init(tn, &act_xt_ops);
} }
static void __net_exit xt_exit_net(struct net *net) static void __net_exit xt_exit_net(struct net *net)
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <linux/tc_act/tc_mirred.h> #include <linux/tc_act/tc_mirred.h>
#include <net/tc_act/tc_mirred.h> #include <net/tc_act/tc_mirred.h>
#define MIRRED_TAB_MASK 7
static LIST_HEAD(mirred_list); static LIST_HEAD(mirred_list);
static DEFINE_SPINLOCK(mirred_list_lock); static DEFINE_SPINLOCK(mirred_list_lock);
...@@ -94,7 +93,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -94,7 +93,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_MIRRED_PARMS]); parm = nla_data(tb[TCA_MIRRED_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
...@@ -106,14 +105,14 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -106,14 +105,14 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
break; break;
default: default:
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
if (parm->ifindex) { if (parm->ifindex) {
dev = __dev_get_by_index(net, parm->ifindex); dev = __dev_get_by_index(net, parm->ifindex);
if (dev == NULL) { if (dev == NULL) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -ENODEV; return -ENODEV;
} }
mac_header_xmit = dev_is_mac_header_xmit(dev); mac_header_xmit = dev_is_mac_header_xmit(dev);
...@@ -124,13 +123,13 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -124,13 +123,13 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (!exists) { if (!exists) {
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_mirred_ops, bind, true); &act_mirred_ops, bind, true);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -152,7 +151,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -152,7 +151,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
spin_lock_bh(&mirred_list_lock); spin_lock_bh(&mirred_list_lock);
list_add(&m->tcfm_list, &mirred_list); list_add(&m->tcfm_list, &mirred_list);
spin_unlock_bh(&mirred_list_lock); spin_unlock_bh(&mirred_list_lock);
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
} }
return ret; return ret;
...@@ -283,7 +282,7 @@ static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index) ...@@ -283,7 +282,7 @@ static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, mirred_net_id); struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static int mirred_device_event(struct notifier_block *unused, static int mirred_device_event(struct notifier_block *unused,
...@@ -344,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net) ...@@ -344,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, mirred_net_id); struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK); return tc_action_net_init(tn, &act_mirred_ops);
} }
static void __net_exit mirred_exit_net(struct net *net) static void __net_exit mirred_exit_net(struct net *net)
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
#include <net/udp.h> #include <net/udp.h>
#define NAT_TAB_MASK 15
static unsigned int nat_net_id; static unsigned int nat_net_id;
static struct tc_action_ops act_nat_ops; static struct tc_action_ops act_nat_ops;
...@@ -58,16 +56,16 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, ...@@ -58,16 +56,16 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_NAT_PARMS]); parm = nla_data(tb[TCA_NAT_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_nat_ops, bind, false); &act_nat_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
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;
} }
...@@ -83,7 +81,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, ...@@ -83,7 +81,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
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;
} }
...@@ -290,7 +288,7 @@ static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index) ...@@ -290,7 +288,7 @@ static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, nat_net_id); struct tc_action_net *tn = net_generic(net, nat_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_nat_ops = { static struct tc_action_ops act_nat_ops = {
...@@ -309,7 +307,7 @@ static __net_init int nat_init_net(struct net *net) ...@@ -309,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, nat_net_id); struct tc_action_net *tn = net_generic(net, nat_net_id);
return tc_action_net_init(tn, &act_nat_ops, NAT_TAB_MASK); return tc_action_net_init(tn, &act_nat_ops);
} }
static void __net_exit nat_exit_net(struct net *net) static void __net_exit nat_exit_net(struct net *net)
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include <net/tc_act/tc_pedit.h> #include <net/tc_act/tc_pedit.h>
#include <uapi/linux/tc_act/tc_pedit.h> #include <uapi/linux/tc_act/tc_pedit.h>
#define PEDIT_TAB_MASK 15
static unsigned int pedit_net_id; static unsigned int pedit_net_id;
static struct tc_action_ops act_pedit_ops; static struct tc_action_ops act_pedit_ops;
...@@ -168,17 +166,17 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -168,17 +166,17 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (IS_ERR(keys_ex)) if (IS_ERR(keys_ex))
return PTR_ERR(keys_ex); return PTR_ERR(keys_ex);
if (!tcf_hash_check(tn, parm->index, a, bind)) { if (!tcf_idr_check(tn, parm->index, a, bind)) {
if (!parm->nkeys) if (!parm->nkeys)
return -EINVAL; return -EINVAL;
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_pedit_ops, bind, false); &act_pedit_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
p = to_pedit(*a); p = to_pedit(*a);
keys = kmalloc(ksize, GFP_KERNEL); keys = kmalloc(ksize, GFP_KERNEL);
if (keys == NULL) { if (keys == NULL) {
tcf_hash_cleanup(*a, est); tcf_idr_cleanup(*a, est);
kfree(keys_ex); kfree(keys_ex);
return -ENOMEM; return -ENOMEM;
} }
...@@ -186,7 +184,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -186,7 +184,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
} else { } else {
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;
p = to_pedit(*a); p = to_pedit(*a);
...@@ -214,7 +212,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -214,7 +212,7 @@ static int tcf_pedit_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;
} }
...@@ -432,7 +430,7 @@ static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index) ...@@ -432,7 +430,7 @@ static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, pedit_net_id); struct tc_action_net *tn = net_generic(net, pedit_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_pedit_ops = { static struct tc_action_ops act_pedit_ops = {
...@@ -452,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net) ...@@ -452,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, pedit_net_id); struct tc_action_net *tn = net_generic(net, pedit_net_id);
return tc_action_net_init(tn, &act_pedit_ops, PEDIT_TAB_MASK); return tc_action_net_init(tn, &act_pedit_ops);
} }
static void __net_exit pedit_exit_net(struct net *net) static void __net_exit pedit_exit_net(struct net *net)
......
...@@ -40,8 +40,6 @@ struct tcf_police { ...@@ -40,8 +40,6 @@ struct tcf_police {
#define to_police(pc) ((struct tcf_police *)pc) #define to_police(pc) ((struct tcf_police *)pc)
#define POL_TAB_MASK 15
/* old policer structure from before tc actions */ /* old policer structure from before tc actions */
struct tc_police_compat { struct tc_police_compat {
u32 index; u32 index;
...@@ -101,18 +99,18 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, ...@@ -101,18 +99,18 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_POLICE_TBF]); parm = nla_data(tb[TCA_POLICE_TBF]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, NULL, a, ret = tcf_idr_create(tn, parm->index, NULL, a,
&act_police_ops, bind, false); &act_police_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -188,7 +186,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, ...@@ -188,7 +186,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
return ret; return ret;
police->tcfp_t_c = ktime_get_ns(); police->tcfp_t_c = ktime_get_ns();
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
...@@ -196,7 +194,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, ...@@ -196,7 +194,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
qdisc_put_rtab(P_tab); qdisc_put_rtab(P_tab);
qdisc_put_rtab(R_tab); qdisc_put_rtab(R_tab);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_cleanup(*a, est); tcf_idr_cleanup(*a, est);
return err; return err;
} }
...@@ -310,7 +308,7 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index) ...@@ -310,7 +308,7 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, police_net_id); struct tc_action_net *tn = net_generic(net, police_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
MODULE_AUTHOR("Alexey Kuznetsov"); MODULE_AUTHOR("Alexey Kuznetsov");
...@@ -333,7 +331,7 @@ static __net_init int police_init_net(struct net *net) ...@@ -333,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, police_net_id); struct tc_action_net *tn = net_generic(net, police_net_id);
return tc_action_net_init(tn, &act_police_ops, POL_TAB_MASK); return tc_action_net_init(tn, &act_police_ops);
} }
static void __net_exit police_exit_net(struct net *net) static void __net_exit police_exit_net(struct net *net)
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#define SAMPLE_TAB_MASK 7
static unsigned int sample_net_id; static unsigned int sample_net_id;
static struct tc_action_ops act_sample_ops; static struct tc_action_ops act_sample_ops;
...@@ -59,18 +58,18 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, ...@@ -59,18 +58,18 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_SAMPLE_PARMS]); parm = nla_data(tb[TCA_SAMPLE_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_sample_ops, bind, false); &act_sample_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -82,7 +81,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, ...@@ -82,7 +81,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
psample_group = psample_group_get(net, s->psample_group_num); psample_group = psample_group_get(net, s->psample_group_num);
if (!psample_group) { if (!psample_group) {
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -ENOMEM; return -ENOMEM;
} }
RCU_INIT_POINTER(s->psample_group, psample_group); RCU_INIT_POINTER(s->psample_group, psample_group);
...@@ -93,7 +92,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, ...@@ -93,7 +92,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
} }
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
} }
...@@ -221,7 +220,7 @@ static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index) ...@@ -221,7 +220,7 @@ static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, sample_net_id); struct tc_action_net *tn = net_generic(net, sample_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_sample_ops = { static struct tc_action_ops act_sample_ops = {
...@@ -241,7 +240,7 @@ static __net_init int sample_init_net(struct net *net) ...@@ -241,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, sample_net_id); struct tc_action_net *tn = net_generic(net, sample_net_id);
return tc_action_net_init(tn, &act_sample_ops, SAMPLE_TAB_MASK); return tc_action_net_init(tn, &act_sample_ops);
} }
static void __net_exit sample_exit_net(struct net *net) static void __net_exit sample_exit_net(struct net *net)
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include <linux/tc_act/tc_defact.h> #include <linux/tc_act/tc_defact.h>
#include <net/tc_act/tc_defact.h> #include <net/tc_act/tc_defact.h>
#define SIMP_TAB_MASK 7
static unsigned int simp_net_id; static unsigned int simp_net_id;
static struct tc_action_ops act_simp_ops; static struct tc_action_ops act_simp_ops;
...@@ -102,28 +100,28 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, ...@@ -102,28 +100,28 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_DEF_PARMS]); parm = nla_data(tb[TCA_DEF_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (tb[TCA_DEF_DATA] == NULL) { if (tb[TCA_DEF_DATA] == NULL) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
defdata = nla_data(tb[TCA_DEF_DATA]); defdata = nla_data(tb[TCA_DEF_DATA]);
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_simp_ops, bind, false); &act_simp_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
d = to_defact(*a); d = to_defact(*a);
ret = alloc_defdata(d, defdata); ret = alloc_defdata(d, defdata);
if (ret < 0) { if (ret < 0) {
tcf_hash_cleanup(*a, est); tcf_idr_cleanup(*a, est);
return ret; return ret;
} }
d->tcf_action = parm->action; d->tcf_action = parm->action;
...@@ -131,7 +129,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, ...@@ -131,7 +129,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
} else { } else {
d = to_defact(*a); d = to_defact(*a);
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
...@@ -139,7 +137,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, ...@@ -139,7 +137,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
} }
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
} }
...@@ -183,7 +181,7 @@ static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index) ...@@ -183,7 +181,7 @@ static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, simp_net_id); struct tc_action_net *tn = net_generic(net, simp_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_simp_ops = { static struct tc_action_ops act_simp_ops = {
...@@ -203,7 +201,7 @@ static __net_init int simp_init_net(struct net *net) ...@@ -203,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, simp_net_id); struct tc_action_net *tn = net_generic(net, simp_net_id);
return tc_action_net_init(tn, &act_simp_ops, SIMP_TAB_MASK); return tc_action_net_init(tn, &act_simp_ops);
} }
static void __net_exit simp_exit_net(struct net *net) static void __net_exit simp_exit_net(struct net *net)
......
...@@ -27,8 +27,6 @@ ...@@ -27,8 +27,6 @@
#include <linux/tc_act/tc_skbedit.h> #include <linux/tc_act/tc_skbedit.h>
#include <net/tc_act/tc_skbedit.h> #include <net/tc_act/tc_skbedit.h>
#define SKBEDIT_TAB_MASK 15
static unsigned int skbedit_net_id; static unsigned int skbedit_net_id;
static struct tc_action_ops act_skbedit_ops; static struct tc_action_ops act_skbedit_ops;
...@@ -118,18 +116,18 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, ...@@ -118,18 +116,18 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_SKBEDIT_PARMS]); parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
if (!flags) { if (!flags) {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_skbedit_ops, bind, false); &act_skbedit_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
...@@ -137,7 +135,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, ...@@ -137,7 +135,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
d = to_skbedit(*a); d = to_skbedit(*a);
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -163,7 +161,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, ...@@ -163,7 +161,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&d->tcf_lock); spin_unlock_bh(&d->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;
} }
...@@ -221,7 +219,7 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index) ...@@ -221,7 +219,7 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, skbedit_net_id); struct tc_action_net *tn = net_generic(net, skbedit_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_skbedit_ops = { static struct tc_action_ops act_skbedit_ops = {
...@@ -240,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net) ...@@ -240,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbedit_net_id); struct tc_action_net *tn = net_generic(net, skbedit_net_id);
return tc_action_net_init(tn, &act_skbedit_ops, SKBEDIT_TAB_MASK); return tc_action_net_init(tn, &act_skbedit_ops);
} }
static void __net_exit skbedit_exit_net(struct net *net) static void __net_exit skbedit_exit_net(struct net *net)
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include <linux/tc_act/tc_skbmod.h> #include <linux/tc_act/tc_skbmod.h>
#include <net/tc_act/tc_skbmod.h> #include <net/tc_act/tc_skbmod.h>
#define SKBMOD_TAB_MASK 15
static unsigned int skbmod_net_id; static unsigned int skbmod_net_id;
static struct tc_action_ops act_skbmod_ops; static struct tc_action_ops act_skbmod_ops;
...@@ -129,7 +127,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, ...@@ -129,7 +127,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
if (parm->flags & SKBMOD_F_SWAPMAC) if (parm->flags & SKBMOD_F_SWAPMAC)
lflags = SKBMOD_F_SWAPMAC; lflags = SKBMOD_F_SWAPMAC;
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
...@@ -137,14 +135,14 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, ...@@ -137,14 +135,14 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
return -EINVAL; return -EINVAL;
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_skbmod_ops, bind, true); &act_skbmod_ops, bind, true);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -155,7 +153,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, ...@@ -155,7 +153,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL);
if (unlikely(!p)) { if (unlikely(!p)) {
if (ovr) if (ovr)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -ENOMEM; return -ENOMEM;
} }
...@@ -182,7 +180,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, ...@@ -182,7 +180,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
kfree_rcu(p_old, rcu); kfree_rcu(p_old, rcu);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
} }
...@@ -245,7 +243,7 @@ static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index) ...@@ -245,7 +243,7 @@ static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, skbmod_net_id); struct tc_action_net *tn = net_generic(net, skbmod_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_skbmod_ops = { static struct tc_action_ops act_skbmod_ops = {
...@@ -265,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net) ...@@ -265,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbmod_net_id); struct tc_action_net *tn = net_generic(net, skbmod_net_id);
return tc_action_net_init(tn, &act_skbmod_ops, SKBMOD_TAB_MASK); return tc_action_net_init(tn, &act_skbmod_ops);
} }
static void __net_exit skbmod_exit_net(struct net *net) static void __net_exit skbmod_exit_net(struct net *net)
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include <linux/tc_act/tc_tunnel_key.h> #include <linux/tc_act/tc_tunnel_key.h>
#include <net/tc_act/tc_tunnel_key.h> #include <net/tc_act/tc_tunnel_key.h>
#define TUNNEL_KEY_TAB_MASK 15
static unsigned int tunnel_key_net_id; static unsigned int tunnel_key_net_id;
static struct tc_action_ops act_tunnel_key_ops; static struct tc_action_ops act_tunnel_key_ops;
...@@ -100,7 +98,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, ...@@ -100,7 +98,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]); parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
...@@ -159,14 +157,14 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, ...@@ -159,14 +157,14 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
} }
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_tunnel_key_ops, bind, true); &act_tunnel_key_ops, bind, true);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -177,7 +175,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, ...@@ -177,7 +175,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
if (unlikely(!params_new)) { if (unlikely(!params_new)) {
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -ENOMEM; return -ENOMEM;
} }
...@@ -193,13 +191,13 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, ...@@ -193,13 +191,13 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
kfree_rcu(params_old, rcu); kfree_rcu(params_old, rcu);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_hash_insert(tn, *a); tcf_idr_insert(tn, *a);
return ret; return ret;
err_out: err_out:
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return ret; return ret;
} }
...@@ -304,7 +302,7 @@ static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) ...@@ -304,7 +302,7 @@ static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_tunnel_key_ops = { static struct tc_action_ops act_tunnel_key_ops = {
...@@ -324,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net) ...@@ -324,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
return tc_action_net_init(tn, &act_tunnel_key_ops, TUNNEL_KEY_TAB_MASK); return tc_action_net_init(tn, &act_tunnel_key_ops);
} }
static void __net_exit tunnel_key_exit_net(struct net *net) static void __net_exit tunnel_key_exit_net(struct net *net)
......
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include <linux/tc_act/tc_vlan.h> #include <linux/tc_act/tc_vlan.h>
#include <net/tc_act/tc_vlan.h> #include <net/tc_act/tc_vlan.h>
#define VLAN_TAB_MASK 15
static unsigned int vlan_net_id; static unsigned int vlan_net_id;
static struct tc_action_ops act_vlan_ops; static struct tc_action_ops act_vlan_ops;
...@@ -128,7 +126,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, ...@@ -128,7 +126,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_VLAN_PARMS]) if (!tb[TCA_VLAN_PARMS])
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_VLAN_PARMS]); parm = nla_data(tb[TCA_VLAN_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind); exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind) if (exists && bind)
return 0; return 0;
...@@ -139,13 +137,13 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, ...@@ -139,13 +137,13 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
case TCA_VLAN_ACT_MODIFY: case TCA_VLAN_ACT_MODIFY:
if (!tb[TCA_VLAN_PUSH_VLAN_ID]) { if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
if (push_vid >= VLAN_VID_MASK) { if (push_vid >= VLAN_VID_MASK) {
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -ERANGE; return -ERANGE;
} }
...@@ -167,20 +165,20 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, ...@@ -167,20 +165,20 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
break; break;
default: default:
if (exists) if (exists)
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
return -EINVAL; return -EINVAL;
} }
action = parm->v_action; action = parm->v_action;
if (!exists) { if (!exists) {
ret = tcf_hash_create(tn, parm->index, est, a, ret = tcf_idr_create(tn, parm->index, est, a,
&act_vlan_ops, bind, false); &act_vlan_ops, bind, false);
if (ret) if (ret)
return ret; return ret;
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else { } else {
tcf_hash_release(*a, bind); tcf_idr_release(*a, bind);
if (!ovr) if (!ovr)
return -EEXIST; return -EEXIST;
} }
...@@ -199,7 +197,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, ...@@ -199,7 +197,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
spin_unlock_bh(&v->tcf_lock); spin_unlock_bh(&v->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;
} }
...@@ -252,7 +250,7 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index) ...@@ -252,7 +250,7 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index)
{ {
struct tc_action_net *tn = net_generic(net, vlan_net_id); struct tc_action_net *tn = net_generic(net, vlan_net_id);
return tcf_hash_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static struct tc_action_ops act_vlan_ops = { static struct tc_action_ops act_vlan_ops = {
...@@ -271,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net) ...@@ -271,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, vlan_net_id); struct tc_action_net *tn = net_generic(net, vlan_net_id);
return tc_action_net_init(tn, &act_vlan_ops, VLAN_TAB_MASK); return tc_action_net_init(tn, &act_vlan_ops);
} }
static void __net_exit vlan_exit_net(struct net *net) static void __net_exit vlan_exit_net(struct net *net)
......
...@@ -68,7 +68,6 @@ struct cls_fl_head { ...@@ -68,7 +68,6 @@ struct cls_fl_head {
struct rhashtable ht; struct rhashtable ht;
struct fl_flow_mask mask; struct fl_flow_mask mask;
struct flow_dissector dissector; struct flow_dissector dissector;
u32 hgen;
bool mask_assigned; bool mask_assigned;
struct list_head filters; struct list_head filters;
struct rhashtable_params ht_params; struct rhashtable_params ht_params;
...@@ -76,6 +75,7 @@ struct cls_fl_head { ...@@ -76,6 +75,7 @@ struct cls_fl_head {
struct work_struct work; struct work_struct work;
struct rcu_head rcu; struct rcu_head rcu;
}; };
struct idr handle_idr;
}; };
struct cls_fl_filter { struct cls_fl_filter {
...@@ -210,6 +210,7 @@ static int fl_init(struct tcf_proto *tp) ...@@ -210,6 +210,7 @@ static int fl_init(struct tcf_proto *tp)
INIT_LIST_HEAD_RCU(&head->filters); INIT_LIST_HEAD_RCU(&head->filters);
rcu_assign_pointer(tp->root, head); rcu_assign_pointer(tp->root, head);
idr_init(&head->handle_idr);
return 0; return 0;
} }
...@@ -295,6 +296,9 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) ...@@ -295,6 +296,9 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
{ {
struct cls_fl_head *head = rtnl_dereference(tp->root);
idr_remove_ext(&head->handle_idr, f->handle);
list_del_rcu(&f->list); list_del_rcu(&f->list);
if (!tc_skip_hw(f->flags)) if (!tc_skip_hw(f->flags))
fl_hw_destroy_filter(tp, f); fl_hw_destroy_filter(tp, f);
...@@ -327,6 +331,7 @@ static void fl_destroy(struct tcf_proto *tp) ...@@ -327,6 +331,7 @@ static void fl_destroy(struct tcf_proto *tp)
list_for_each_entry_safe(f, next, &head->filters, list) list_for_each_entry_safe(f, next, &head->filters, list)
__fl_delete(tp, f); __fl_delete(tp, f);
idr_destroy(&head->handle_idr);
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
call_rcu(&head->rcu, fl_destroy_rcu); call_rcu(&head->rcu, fl_destroy_rcu);
...@@ -335,12 +340,8 @@ static void fl_destroy(struct tcf_proto *tp) ...@@ -335,12 +340,8 @@ static void fl_destroy(struct tcf_proto *tp)
static void *fl_get(struct tcf_proto *tp, u32 handle) static void *fl_get(struct tcf_proto *tp, u32 handle)
{ {
struct cls_fl_head *head = rtnl_dereference(tp->root); struct cls_fl_head *head = rtnl_dereference(tp->root);
struct cls_fl_filter *f;
list_for_each_entry(f, &head->filters, list) return idr_find_ext(&head->handle_idr, handle);
if (f->handle == handle)
return f;
return NULL;
} }
static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
...@@ -859,27 +860,6 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp, ...@@ -859,27 +860,6 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
return 0; return 0;
} }
static u32 fl_grab_new_handle(struct tcf_proto *tp,
struct cls_fl_head *head)
{
unsigned int i = 0x80000000;
u32 handle;
do {
if (++head->hgen == 0x7FFFFFFF)
head->hgen = 1;
} while (--i > 0 && fl_get(tp, head->hgen));
if (unlikely(i == 0)) {
pr_err("Insufficient number of handles\n");
handle = 0;
} else {
handle = head->hgen;
}
return handle;
}
static int fl_change(struct net *net, struct sk_buff *in_skb, static int fl_change(struct net *net, struct sk_buff *in_skb,
struct tcf_proto *tp, unsigned long base, struct tcf_proto *tp, unsigned long base,
u32 handle, struct nlattr **tca, u32 handle, struct nlattr **tca,
...@@ -890,6 +870,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -890,6 +870,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
struct cls_fl_filter *fnew; struct cls_fl_filter *fnew;
struct nlattr **tb; struct nlattr **tb;
struct fl_flow_mask mask = {}; struct fl_flow_mask mask = {};
unsigned long idr_index;
int err; int err;
if (!tca[TCA_OPTIONS]) if (!tca[TCA_OPTIONS])
...@@ -920,13 +901,21 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -920,13 +901,21 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
goto errout; goto errout;
if (!handle) { if (!handle) {
handle = fl_grab_new_handle(tp, head); err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
if (!handle) { 1, 0x80000000, GFP_KERNEL);
err = -EINVAL; if (err)
goto errout; goto errout;
} fnew->handle = idr_index;
}
/* user specifies a handle and it doesn't exist */
if (handle && !fold) {
err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
handle, handle + 1, GFP_KERNEL);
if (err)
goto errout;
fnew->handle = idr_index;
} }
fnew->handle = handle;
if (tb[TCA_FLOWER_FLAGS]) { if (tb[TCA_FLOWER_FLAGS]) {
fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
...@@ -980,6 +969,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -980,6 +969,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
*arg = fnew; *arg = fnew;
if (fold) { if (fold) {
fnew->handle = handle;
idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
list_replace_rcu(&fold->list, &fnew->list); list_replace_rcu(&fold->list, &fnew->list);
tcf_unbind_filter(tp, &fold->res); tcf_unbind_filter(tp, &fold->res);
call_rcu(&fold->rcu, fl_destroy_filter); call_rcu(&fold->rcu, fl_destroy_filter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment