Commit 1785e8f4 authored by Vitaly Lavrov's avatar Vitaly Lavrov Committed by Jozsef Kadlecsik

netfiler: ipset: Add net namespace for ipset

This patch adds netns support for ipset.

Major changes were made in ip_set_core.c and ip_set.h.
Global variables are moved to per net namespace.
Added initialization code and the destruction of the network namespace ipset subsystem.
In the prototypes of public functions ip_set_* added parameter "struct net*".

The remaining corrections related to the change prototypes of public functions ip_set_*.

The patch for git://git.netfilter.org/ipset.git commit 6a4ec96c0b8caac5c35474e40e319704d92ca347
Signed-off-by: default avatarVitaly Lavrov <lve@guap.ru>
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
parent 3fd986b3
...@@ -184,7 +184,8 @@ struct ip_set_type { ...@@ -184,7 +184,8 @@ struct ip_set_type {
u8 revision_min, revision_max; u8 revision_min, revision_max;
/* Create set */ /* Create set */
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); int (*create)(struct net *net, struct ip_set *set,
struct nlattr *tb[], u32 flags);
/* Attribute policies */ /* Attribute policies */
const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1];
...@@ -316,12 +317,13 @@ ip_set_init_counter(struct ip_set_counter *counter, ...@@ -316,12 +317,13 @@ ip_set_init_counter(struct ip_set_counter *counter,
} }
/* register and unregister set references */ /* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); extern ip_set_id_t ip_set_get_byname(struct net *net,
extern void ip_set_put_byindex(ip_set_id_t index); const char *name, struct ip_set **set);
extern const char *ip_set_name_byindex(ip_set_id_t index); extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
extern ip_set_id_t ip_set_nfnl_get(const char *name); extern const char *ip_set_name_byindex(struct net *net, ip_set_id_t index);
extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); extern ip_set_id_t ip_set_nfnl_get(struct net *net, const char *name);
extern void ip_set_nfnl_put(ip_set_id_t index); extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
extern void ip_set_nfnl_put(struct net *net, ip_set_id_t index);
/* API for iptables set match, and SET target */ /* API for iptables set match, and SET target */
......
...@@ -242,7 +242,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, ...@@ -242,7 +242,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
} }
static int static int
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
u32 flags)
{ {
struct bitmap_ip *map; struct bitmap_ip *map;
u32 first_ip = 0, last_ip = 0, hosts; u32 first_ip = 0, last_ip = 0, hosts;
......
...@@ -309,7 +309,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, ...@@ -309,7 +309,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
} }
static int static int
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
u32 flags) u32 flags)
{ {
u32 first_ip = 0, last_ip = 0; u32 first_ip = 0, last_ip = 0;
......
...@@ -228,7 +228,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, ...@@ -228,7 +228,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
} }
static int static int
bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags) bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
u32 flags)
{ {
struct bitmap_port *map; struct bitmap_port *map;
u16 first_port, last_port; u16 first_port, last_port;
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
...@@ -27,8 +29,17 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */ ...@@ -27,8 +29,17 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */
static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */
static struct ip_set * __rcu *ip_set_list; /* all individual sets */ struct ip_set_net {
static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ struct ip_set * __rcu *ip_set_list; /* all individual sets */
ip_set_id_t ip_set_max; /* max number of sets */
int is_deleted; /* deleted by ip_set_net_exit */
};
static int ip_set_net_id __read_mostly;
static inline struct ip_set_net *ip_set_pernet(struct net *net)
{
return net_generic(net, ip_set_net_id);
}
#define IP_SET_INC 64 #define IP_SET_INC 64
#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0)
...@@ -45,8 +56,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); ...@@ -45,8 +56,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
/* When the nfnl mutex is held: */ /* When the nfnl mutex is held: */
#define nfnl_dereference(p) \ #define nfnl_dereference(p) \
rcu_dereference_protected(p, 1) rcu_dereference_protected(p, 1)
#define nfnl_set(id) \ #define nfnl_set(inst, id) \
nfnl_dereference(ip_set_list)[id] nfnl_dereference((inst)->ip_set_list)[id]
/* /*
* The set types are implemented in modules and registered set types * The set types are implemented in modules and registered set types
...@@ -434,13 +445,14 @@ __ip_set_put(struct ip_set *set) ...@@ -434,13 +445,14 @@ __ip_set_put(struct ip_set *set)
*/ */
static inline struct ip_set * static inline struct ip_set *
ip_set_rcu_get(ip_set_id_t index) ip_set_rcu_get(struct net *net, ip_set_id_t index)
{ {
struct ip_set *set; struct ip_set *set;
struct ip_set_net *inst = ip_set_pernet(net);
rcu_read_lock(); rcu_read_lock();
/* ip_set_list itself needs to be protected */ /* ip_set_list itself needs to be protected */
set = rcu_dereference(ip_set_list)[index]; set = rcu_dereference(inst->ip_set_list)[index];
rcu_read_unlock(); rcu_read_unlock();
return set; return set;
...@@ -450,7 +462,8 @@ int ...@@ -450,7 +462,8 @@ int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt) const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(
dev_net(par->in ? par->in : par->out), index);
int ret = 0; int ret = 0;
BUG_ON(set == NULL); BUG_ON(set == NULL);
...@@ -488,7 +501,8 @@ int ...@@ -488,7 +501,8 @@ int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt) const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(
dev_net(par->in ? par->in : par->out), index);
int ret; int ret;
BUG_ON(set == NULL); BUG_ON(set == NULL);
...@@ -510,7 +524,8 @@ int ...@@ -510,7 +524,8 @@ int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt) const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(
dev_net(par->in ? par->in : par->out), index);
int ret = 0; int ret = 0;
BUG_ON(set == NULL); BUG_ON(set == NULL);
...@@ -534,14 +549,15 @@ EXPORT_SYMBOL_GPL(ip_set_del); ...@@ -534,14 +549,15 @@ EXPORT_SYMBOL_GPL(ip_set_del);
* *
*/ */
ip_set_id_t ip_set_id_t
ip_set_get_byname(const char *name, struct ip_set **set) ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
{ {
ip_set_id_t i, index = IPSET_INVALID_ID; ip_set_id_t i, index = IPSET_INVALID_ID;
struct ip_set *s; struct ip_set *s;
struct ip_set_net *inst = ip_set_pernet(net);
rcu_read_lock(); rcu_read_lock();
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = rcu_dereference(ip_set_list)[i]; s = rcu_dereference(inst->ip_set_list)[i];
if (s != NULL && STREQ(s->name, name)) { if (s != NULL && STREQ(s->name, name)) {
__ip_set_get(s); __ip_set_get(s);
index = i; index = i;
...@@ -561,17 +577,26 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname); ...@@ -561,17 +577,26 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
* to be valid, after calling this function. * to be valid, after calling this function.
* *
*/ */
void
ip_set_put_byindex(ip_set_id_t index) static inline void
__ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)
{ {
struct ip_set *set; struct ip_set *set;
rcu_read_lock(); rcu_read_lock();
set = rcu_dereference(ip_set_list)[index]; set = rcu_dereference(inst->ip_set_list)[index];
if (set != NULL) if (set != NULL)
__ip_set_put(set); __ip_set_put(set);
rcu_read_unlock(); rcu_read_unlock();
} }
void
ip_set_put_byindex(struct net *net, ip_set_id_t index)
{
struct ip_set_net *inst = ip_set_pernet(net);
__ip_set_put_byindex(inst, index);
}
EXPORT_SYMBOL_GPL(ip_set_put_byindex); EXPORT_SYMBOL_GPL(ip_set_put_byindex);
/* /*
...@@ -582,9 +607,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex); ...@@ -582,9 +607,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
* *
*/ */
const char * const char *
ip_set_name_byindex(ip_set_id_t index) ip_set_name_byindex(struct net *net, ip_set_id_t index)
{ {
const struct ip_set *set = ip_set_rcu_get(index); const struct ip_set *set = ip_set_rcu_get(net, index);
BUG_ON(set == NULL); BUG_ON(set == NULL);
BUG_ON(set->ref == 0); BUG_ON(set->ref == 0);
...@@ -606,14 +631,15 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex); ...@@ -606,14 +631,15 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex);
* The nfnl mutex is used in the function. * The nfnl mutex is used in the function.
*/ */
ip_set_id_t ip_set_id_t
ip_set_nfnl_get(const char *name) ip_set_nfnl_get(struct net *net, const char *name)
{ {
ip_set_id_t i, index = IPSET_INVALID_ID; ip_set_id_t i, index = IPSET_INVALID_ID;
struct ip_set *s; struct ip_set *s;
struct ip_set_net *inst = ip_set_pernet(net);
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s != NULL && STREQ(s->name, name)) { if (s != NULL && STREQ(s->name, name)) {
__ip_set_get(s); __ip_set_get(s);
index = i; index = i;
...@@ -633,15 +659,16 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get); ...@@ -633,15 +659,16 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get);
* The nfnl mutex is used in the function. * The nfnl mutex is used in the function.
*/ */
ip_set_id_t ip_set_id_t
ip_set_nfnl_get_byindex(ip_set_id_t index) ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
{ {
struct ip_set *set; struct ip_set *set;
struct ip_set_net *inst = ip_set_pernet(net);
if (index > ip_set_max) if (index > inst->ip_set_max)
return IPSET_INVALID_ID; return IPSET_INVALID_ID;
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
set = nfnl_set(index); set = nfnl_set(inst, index);
if (set) if (set)
__ip_set_get(set); __ip_set_get(set);
else else
...@@ -660,13 +687,17 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex); ...@@ -660,13 +687,17 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex);
* The nfnl mutex is used in the function. * The nfnl mutex is used in the function.
*/ */
void void
ip_set_nfnl_put(ip_set_id_t index) ip_set_nfnl_put(struct net *net, ip_set_id_t index)
{ {
struct ip_set *set; struct ip_set *set;
struct ip_set_net *inst = ip_set_pernet(net);
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
set = nfnl_set(index); if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */
if (set != NULL) set = nfnl_set(inst, index);
__ip_set_put(set); if (set != NULL)
__ip_set_put(set);
}
nfnl_unlock(NFNL_SUBSYS_IPSET); nfnl_unlock(NFNL_SUBSYS_IPSET);
} }
EXPORT_SYMBOL_GPL(ip_set_nfnl_put); EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
...@@ -724,14 +755,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = { ...@@ -724,14 +755,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = {
}; };
static struct ip_set * static struct ip_set *
find_set_and_id(const char *name, ip_set_id_t *id) find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
{ {
struct ip_set *set = NULL; struct ip_set *set = NULL;
ip_set_id_t i; ip_set_id_t i;
*id = IPSET_INVALID_ID; *id = IPSET_INVALID_ID;
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
set = nfnl_set(i); set = nfnl_set(inst, i);
if (set != NULL && STREQ(set->name, name)) { if (set != NULL && STREQ(set->name, name)) {
*id = i; *id = i;
break; break;
...@@ -741,22 +772,23 @@ find_set_and_id(const char *name, ip_set_id_t *id) ...@@ -741,22 +772,23 @@ find_set_and_id(const char *name, ip_set_id_t *id)
} }
static inline struct ip_set * static inline struct ip_set *
find_set(const char *name) find_set(struct ip_set_net *inst, const char *name)
{ {
ip_set_id_t id; ip_set_id_t id;
return find_set_and_id(name, &id); return find_set_and_id(inst, name, &id);
} }
static int static int
find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
struct ip_set **set)
{ {
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
*index = IPSET_INVALID_ID; *index = IPSET_INVALID_ID;
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s == NULL) { if (s == NULL) {
if (*index == IPSET_INVALID_ID) if (*index == IPSET_INVALID_ID)
*index = i; *index = i;
...@@ -785,6 +817,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -785,6 +817,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct net *net = sock_net(ctnl);
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set, *clash = NULL; struct ip_set *set, *clash = NULL;
ip_set_id_t index = IPSET_INVALID_ID; ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
...@@ -843,7 +877,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -843,7 +877,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
goto put_out; goto put_out;
} }
ret = set->type->create(set, tb, flags); ret = set->type->create(net, set, tb, flags);
if (ret != 0) if (ret != 0)
goto put_out; goto put_out;
...@@ -854,7 +888,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -854,7 +888,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
* by the nfnl mutex. Find the first free index in ip_set_list * by the nfnl mutex. Find the first free index in ip_set_list
* and check clashing. * and check clashing.
*/ */
ret = find_free_id(set->name, &index, &clash); ret = find_free_id(inst, set->name, &index, &clash);
if (ret == -EEXIST) { if (ret == -EEXIST) {
/* If this is the same set and requested, ignore error */ /* If this is the same set and requested, ignore error */
if ((flags & IPSET_FLAG_EXIST) && if ((flags & IPSET_FLAG_EXIST) &&
...@@ -867,9 +901,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -867,9 +901,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
goto cleanup; goto cleanup;
} else if (ret == -IPSET_ERR_MAX_SETS) { } else if (ret == -IPSET_ERR_MAX_SETS) {
struct ip_set **list, **tmp; struct ip_set **list, **tmp;
ip_set_id_t i = ip_set_max + IP_SET_INC; ip_set_id_t i = inst->ip_set_max + IP_SET_INC;
if (i < ip_set_max || i == IPSET_INVALID_ID) if (i < inst->ip_set_max || i == IPSET_INVALID_ID)
/* Wraparound */ /* Wraparound */
goto cleanup; goto cleanup;
...@@ -877,14 +911,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -877,14 +911,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
if (!list) if (!list)
goto cleanup; goto cleanup;
/* nfnl mutex is held, both lists are valid */ /* nfnl mutex is held, both lists are valid */
tmp = nfnl_dereference(ip_set_list); tmp = nfnl_dereference(inst->ip_set_list);
memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max); memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max);
rcu_assign_pointer(ip_set_list, list); rcu_assign_pointer(inst->ip_set_list, list);
/* Make sure all current packets have passed through */ /* Make sure all current packets have passed through */
synchronize_net(); synchronize_net();
/* Use new list */ /* Use new list */
index = ip_set_max; index = inst->ip_set_max;
ip_set_max = i; inst->ip_set_max = i;
kfree(tmp); kfree(tmp);
ret = 0; ret = 0;
} else if (ret) } else if (ret)
...@@ -894,7 +928,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -894,7 +928,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
* Finally! Add our shiny new set to the list, and be done. * Finally! Add our shiny new set to the list, and be done.
*/ */
pr_debug("create: '%s' created with index %u!\n", set->name, index); pr_debug("create: '%s' created with index %u!\n", set->name, index);
nfnl_set(index) = set; nfnl_set(inst, index) = set;
return ret; return ret;
...@@ -917,12 +951,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = { ...@@ -917,12 +951,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
}; };
static void static void
ip_set_destroy_set(ip_set_id_t index) ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
{ {
struct ip_set *set = nfnl_set(index); struct ip_set *set = nfnl_set(inst, index);
pr_debug("set: %s\n", set->name); pr_debug("set: %s\n", set->name);
nfnl_set(index) = NULL; nfnl_set(inst, index) = NULL;
/* Must call it without holding any lock */ /* Must call it without holding any lock */
set->variant->destroy(set); set->variant->destroy(set);
...@@ -935,6 +969,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, ...@@ -935,6 +969,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
int ret = 0; int ret = 0;
...@@ -954,21 +989,22 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, ...@@ -954,21 +989,22 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
*/ */
read_lock_bh(&ip_set_ref_lock); read_lock_bh(&ip_set_ref_lock);
if (!attr[IPSET_ATTR_SETNAME]) { if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s != NULL && s->ref) { if (s != NULL && s->ref) {
ret = -IPSET_ERR_BUSY; ret = -IPSET_ERR_BUSY;
goto out; goto out;
} }
} }
read_unlock_bh(&ip_set_ref_lock); read_unlock_bh(&ip_set_ref_lock);
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s != NULL) if (s != NULL)
ip_set_destroy_set(i); ip_set_destroy_set(inst, i);
} }
} else { } else {
s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i); s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
&i);
if (s == NULL) { if (s == NULL) {
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
...@@ -978,7 +1014,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, ...@@ -978,7 +1014,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
} }
read_unlock_bh(&ip_set_ref_lock); read_unlock_bh(&ip_set_ref_lock);
ip_set_destroy_set(i); ip_set_destroy_set(inst, i);
} }
return 0; return 0;
out: out:
...@@ -1003,6 +1039,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, ...@@ -1003,6 +1039,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
...@@ -1010,13 +1047,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, ...@@ -1010,13 +1047,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (!attr[IPSET_ATTR_SETNAME]) { if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s != NULL) if (s != NULL)
ip_set_flush_set(s); ip_set_flush_set(s);
} }
} else { } else {
s = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); s = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (s == NULL) if (s == NULL)
return -ENOENT; return -ENOENT;
...@@ -1042,6 +1079,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, ...@@ -1042,6 +1079,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set, *s; struct ip_set *set, *s;
const char *name2; const char *name2;
ip_set_id_t i; ip_set_id_t i;
...@@ -1052,7 +1090,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, ...@@ -1052,7 +1090,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME2] == NULL)) attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1063,8 +1101,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, ...@@ -1063,8 +1101,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
} }
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < inst->ip_set_max; i++) {
s = nfnl_set(i); s = nfnl_set(inst, i);
if (s != NULL && STREQ(s->name, name2)) { if (s != NULL && STREQ(s->name, name2)) {
ret = -IPSET_ERR_EXIST_SETNAME2; ret = -IPSET_ERR_EXIST_SETNAME2;
goto out; goto out;
...@@ -1091,6 +1129,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -1091,6 +1129,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *from, *to; struct ip_set *from, *to;
ip_set_id_t from_id, to_id; ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN]; char from_name[IPSET_MAXNAMELEN];
...@@ -1100,11 +1139,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -1100,11 +1139,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME2] == NULL)) attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id); from = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
&from_id);
if (from == NULL) if (from == NULL)
return -ENOENT; return -ENOENT;
to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id); to = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME2]),
&to_id);
if (to == NULL) if (to == NULL)
return -IPSET_ERR_EXIST_SETNAME2; return -IPSET_ERR_EXIST_SETNAME2;
...@@ -1121,8 +1162,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -1121,8 +1162,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
write_lock_bh(&ip_set_ref_lock); write_lock_bh(&ip_set_ref_lock);
swap(from->ref, to->ref); swap(from->ref, to->ref);
nfnl_set(from_id) = to; nfnl_set(inst, from_id) = to;
nfnl_set(to_id) = from; nfnl_set(inst, to_id) = from;
write_unlock_bh(&ip_set_ref_lock); write_unlock_bh(&ip_set_ref_lock);
return 0; return 0;
...@@ -1141,9 +1182,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -1141,9 +1182,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
static int static int
ip_set_dump_done(struct netlink_callback *cb) ip_set_dump_done(struct netlink_callback *cb)
{ {
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
if (cb->args[2]) { if (cb->args[2]) {
pr_debug("release set %s\n", nfnl_set(cb->args[1])->name); pr_debug("release set %s\n", nfnl_set(inst, cb->args[1])->name);
ip_set_put_byindex((ip_set_id_t) cb->args[1]); __ip_set_put_byindex(inst, (ip_set_id_t) cb->args[1]);
} }
return 0; return 0;
} }
...@@ -1169,6 +1211,7 @@ dump_init(struct netlink_callback *cb) ...@@ -1169,6 +1211,7 @@ dump_init(struct netlink_callback *cb)
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
u32 dump_type; u32 dump_type;
ip_set_id_t index; ip_set_id_t index;
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
/* Second pass, so parser can't fail */ /* Second pass, so parser can't fail */
nla_parse(cda, IPSET_ATTR_CMD_MAX, nla_parse(cda, IPSET_ATTR_CMD_MAX,
...@@ -1182,7 +1225,7 @@ dump_init(struct netlink_callback *cb) ...@@ -1182,7 +1225,7 @@ dump_init(struct netlink_callback *cb)
if (cda[IPSET_ATTR_SETNAME]) { if (cda[IPSET_ATTR_SETNAME]) {
struct ip_set *set; struct ip_set *set;
set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]), set = find_set_and_id(inst, nla_data(cda[IPSET_ATTR_SETNAME]),
&index); &index);
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1210,6 +1253,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1210,6 +1253,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0; unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0;
u32 dump_type, dump_flags; u32 dump_type, dump_flags;
int ret = 0; int ret = 0;
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
if (!cb->args[0]) { if (!cb->args[0]) {
ret = dump_init(cb); ret = dump_init(cb);
...@@ -1223,18 +1267,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1223,18 +1267,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
} }
} }
if (cb->args[1] >= ip_set_max) if (cb->args[1] >= inst->ip_set_max)
goto out; goto out;
dump_type = DUMP_TYPE(cb->args[0]); dump_type = DUMP_TYPE(cb->args[0]);
dump_flags = DUMP_FLAGS(cb->args[0]); dump_flags = DUMP_FLAGS(cb->args[0]);
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; max = dump_type == DUMP_ONE ? cb->args[1] + 1 : inst->ip_set_max;
dump_last: dump_last:
pr_debug("args[0]: %u %u args[1]: %ld\n", pr_debug("args[0]: %u %u args[1]: %ld\n",
dump_type, dump_flags, cb->args[1]); dump_type, dump_flags, cb->args[1]);
for (; cb->args[1] < max; cb->args[1]++) { for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1]; index = (ip_set_id_t) cb->args[1];
set = nfnl_set(index); set = nfnl_set(inst, index);
if (set == NULL) { if (set == NULL) {
if (dump_type == DUMP_ONE) { if (dump_type == DUMP_ONE) {
ret = -ENOENT; ret = -ENOENT;
...@@ -1312,8 +1356,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1312,8 +1356,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
release_refcount: release_refcount:
/* If there was an error or set is done, release set */ /* If there was an error or set is done, release set */
if (ret || !cb->args[2]) { if (ret || !cb->args[2]) {
pr_debug("release set %s\n", nfnl_set(index)->name); pr_debug("release set %s\n", nfnl_set(inst, index)->name);
ip_set_put_byindex(index); __ip_set_put_byindex(inst, index);
cb->args[2] = 0; cb->args[2] = 0;
} }
out: out:
...@@ -1331,6 +1375,8 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, ...@@ -1331,6 +1375,8 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
if (unlikely(protocol_failed(attr))) if (unlikely(protocol_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1338,6 +1384,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, ...@@ -1338,6 +1384,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ip_set_dump_start, .dump = ip_set_dump_start,
.done = ip_set_dump_done, .done = ip_set_dump_done,
.data = (void *)inst
}; };
return netlink_dump_start(ctnl, skb, nlh, &c); return netlink_dump_start(ctnl, skb, nlh, &c);
} }
...@@ -1416,6 +1463,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, ...@@ -1416,6 +1463,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla; const struct nlattr *nla;
...@@ -1434,7 +1482,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, ...@@ -1434,7 +1482,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_LINENO] == NULL)))) attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1470,6 +1518,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, ...@@ -1470,6 +1518,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla; const struct nlattr *nla;
...@@ -1488,7 +1537,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, ...@@ -1488,7 +1537,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_LINENO] == NULL)))) attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1524,6 +1573,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, ...@@ -1524,6 +1573,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
int ret = 0; int ret = 0;
...@@ -1534,7 +1584,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, ...@@ -1534,7 +1584,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
!flag_nested(attr[IPSET_ATTR_DATA]))) !flag_nested(attr[IPSET_ATTR_DATA])))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1559,6 +1609,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb, ...@@ -1559,6 +1609,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const attr[]) const struct nlattr * const attr[])
{ {
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
const struct ip_set *set; const struct ip_set *set;
struct sk_buff *skb2; struct sk_buff *skb2;
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
...@@ -1568,7 +1619,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb, ...@@ -1568,7 +1619,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME] == NULL)) attr[IPSET_ATTR_SETNAME] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -ENOENT; return -ENOENT;
...@@ -1793,8 +1844,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -1793,8 +1844,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
unsigned int *op; unsigned int *op;
void *data; void *data;
int copylen = *len, ret = 0; int copylen = *len, ret = 0;
struct net *net = sock_net(sk);
struct ip_set_net *inst = ip_set_pernet(net);
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (optval != SO_IP_SET) if (optval != SO_IP_SET)
return -EBADF; return -EBADF;
...@@ -1843,7 +1896,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -1843,7 +1896,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
} }
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
find_set_and_id(req_get->set.name, &id); find_set_and_id(inst, req_get->set.name, &id);
req_get->set.index = id; req_get->set.index = id;
nfnl_unlock(NFNL_SUBSYS_IPSET); nfnl_unlock(NFNL_SUBSYS_IPSET);
goto copy; goto copy;
...@@ -1858,10 +1911,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -1858,10 +1911,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
} }
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
find_set_and_id(req_get->set.name, &id); find_set_and_id(inst, req_get->set.name, &id);
req_get->set.index = id; req_get->set.index = id;
if (id != IPSET_INVALID_ID) if (id != IPSET_INVALID_ID)
req_get->family = nfnl_set(id)->family; req_get->family = nfnl_set(inst, id)->family;
nfnl_unlock(NFNL_SUBSYS_IPSET); nfnl_unlock(NFNL_SUBSYS_IPSET);
goto copy; goto copy;
} }
...@@ -1870,12 +1923,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -1870,12 +1923,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
struct ip_set *set; struct ip_set *set;
if (*len != sizeof(struct ip_set_req_get_set) || if (*len != sizeof(struct ip_set_req_get_set) ||
req_get->set.index >= ip_set_max) { req_get->set.index >= inst->ip_set_max) {
ret = -EINVAL; ret = -EINVAL;
goto done; goto done;
} }
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);
set = nfnl_set(req_get->set.index); set = nfnl_set(inst, req_get->set.index);
strncpy(req_get->set.name, set ? set->name : "", strncpy(req_get->set.name, set ? set->name : "",
IPSET_MAXNAMELEN); IPSET_MAXNAMELEN);
nfnl_unlock(NFNL_SUBSYS_IPSET); nfnl_unlock(NFNL_SUBSYS_IPSET);
...@@ -1904,49 +1957,82 @@ static struct nf_sockopt_ops so_set __read_mostly = { ...@@ -1904,49 +1957,82 @@ static struct nf_sockopt_ops so_set __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int __init static int __net_init
ip_set_init(void) ip_set_net_init(struct net *net)
{ {
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set **list; struct ip_set **list;
int ret;
if (max_sets) inst->ip_set_max = max_sets ? max_sets : CONFIG_IP_SET_MAX;
ip_set_max = max_sets; if (inst->ip_set_max >= IPSET_INVALID_ID)
if (ip_set_max >= IPSET_INVALID_ID) inst->ip_set_max = IPSET_INVALID_ID - 1;
ip_set_max = IPSET_INVALID_ID - 1;
list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL); list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL);
if (!list) if (!list)
return -ENOMEM; return -ENOMEM;
inst->is_deleted = 0;
rcu_assign_pointer(inst->ip_set_list, list);
pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
return 0;
}
static void __net_exit
ip_set_net_exit(struct net *net)
{
struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set = NULL;
ip_set_id_t i;
inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
for (i = 0; i < inst->ip_set_max; i++) {
set = nfnl_set(inst, i);
if (set != NULL)
ip_set_destroy_set(inst, i);
}
kfree(rcu_dereference_protected(inst->ip_set_list, 1));
}
static struct pernet_operations ip_set_net_ops = {
.init = ip_set_net_init,
.exit = ip_set_net_exit,
.id = &ip_set_net_id,
.size = sizeof(struct ip_set_net)
};
rcu_assign_pointer(ip_set_list, list); static int __init
ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); ip_set_init(void)
{
int ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
if (ret != 0) { if (ret != 0) {
pr_err("ip_set: cannot register with nfnetlink.\n"); pr_err("ip_set: cannot register with nfnetlink.\n");
kfree(list);
return ret; return ret;
} }
ret = nf_register_sockopt(&so_set); ret = nf_register_sockopt(&so_set);
if (ret != 0) { if (ret != 0) {
pr_err("SO_SET registry failed: %d\n", ret); pr_err("SO_SET registry failed: %d\n", ret);
nfnetlink_subsys_unregister(&ip_set_netlink_subsys); nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
kfree(list);
return ret; return ret;
} }
ret = register_pernet_subsys(&ip_set_net_ops);
pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); if (ret) {
pr_err("ip_set: cannot register pernet_subsys.\n");
nf_unregister_sockopt(&so_set);
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
return ret;
}
return 0; return 0;
} }
static void __exit static void __exit
ip_set_fini(void) ip_set_fini(void)
{ {
struct ip_set **list = rcu_dereference_protected(ip_set_list, 1); unregister_pernet_subsys(&ip_set_net_ops);
/* There can't be any existing set */
nf_unregister_sockopt(&so_set); nf_unregister_sockopt(&so_set);
nfnetlink_subsys_unregister(&ip_set_netlink_subsys); nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
kfree(list);
pr_debug("these are the famous last words\n"); pr_debug("these are the famous last words\n");
} }
......
...@@ -1011,7 +1011,8 @@ static const struct ip_set_type_variant mtype_variant = { ...@@ -1011,7 +1011,8 @@ static const struct ip_set_type_variant mtype_variant = {
#ifdef IP_SET_EMIT_CREATE #ifdef IP_SET_EMIT_CREATE
static int static int
IPSET_TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
struct nlattr *tb[], u32 flags)
{ {
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
......
...@@ -39,6 +39,7 @@ struct set_adt_elem { ...@@ -39,6 +39,7 @@ struct set_adt_elem {
struct list_set { struct list_set {
u32 size; /* size of set list array */ u32 size; /* size of set list array */
struct timer_list gc; /* garbage collection */ struct timer_list gc; /* garbage collection */
struct net *net; /* namespace */
struct set_elem members[0]; /* the set members */ struct set_elem members[0]; /* the set members */
}; };
...@@ -171,7 +172,7 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d, ...@@ -171,7 +172,7 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
if (e->id != IPSET_INVALID_ID) { if (e->id != IPSET_INVALID_ID) {
if (i == map->size - 1) { if (i == map->size - 1) {
/* Last element replaced: e.g. add new,before,last */ /* Last element replaced: e.g. add new,before,last */
ip_set_put_byindex(e->id); ip_set_put_byindex(map->net, e->id);
ip_set_ext_destroy(set, e); ip_set_ext_destroy(set, e);
} else { } else {
struct set_elem *x = list_set_elem(set, map, struct set_elem *x = list_set_elem(set, map,
...@@ -179,7 +180,7 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d, ...@@ -179,7 +180,7 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
/* Last element pushed off */ /* Last element pushed off */
if (x->id != IPSET_INVALID_ID) { if (x->id != IPSET_INVALID_ID) {
ip_set_put_byindex(x->id); ip_set_put_byindex(map->net, x->id);
ip_set_ext_destroy(set, x); ip_set_ext_destroy(set, x);
} }
memmove(list_set_elem(set, map, i + 1), e, memmove(list_set_elem(set, map, i + 1), e,
...@@ -205,7 +206,7 @@ list_set_del(struct ip_set *set, u32 i) ...@@ -205,7 +206,7 @@ list_set_del(struct ip_set *set, u32 i)
struct list_set *map = set->data; struct list_set *map = set->data;
struct set_elem *e = list_set_elem(set, map, i); struct set_elem *e = list_set_elem(set, map, i);
ip_set_put_byindex(e->id); ip_set_put_byindex(map->net, e->id);
ip_set_ext_destroy(set, e); ip_set_ext_destroy(set, e);
if (i < map->size - 1) if (i < map->size - 1)
...@@ -307,7 +308,7 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -307,7 +308,7 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (SET_WITH_COMMENT(set)) if (SET_WITH_COMMENT(set))
ip_set_init_comment(ext_comment(e, set), ext); ip_set_init_comment(ext_comment(e, set), ext);
/* Set is already added to the list */ /* Set is already added to the list */
ip_set_put_byindex(d->id); ip_set_put_byindex(map->net, d->id);
return 0; return 0;
} }
insert: insert:
...@@ -366,6 +367,7 @@ static int ...@@ -366,6 +367,7 @@ static int
list_set_uadt(struct ip_set *set, struct nlattr *tb[], list_set_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
struct list_set *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct set_adt_elem e = { .refid = IPSET_INVALID_ID }; struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
...@@ -385,7 +387,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -385,7 +387,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_extensions(set, tb, &ext); ret = ip_set_get_extensions(set, tb, &ext);
if (ret) if (ret)
return ret; return ret;
e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
if (e.id == IPSET_INVALID_ID) if (e.id == IPSET_INVALID_ID)
return -IPSET_ERR_NAME; return -IPSET_ERR_NAME;
/* "Loop detection" */ /* "Loop detection" */
...@@ -405,7 +407,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -405,7 +407,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (tb[IPSET_ATTR_NAMEREF]) { if (tb[IPSET_ATTR_NAMEREF]) {
e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), e.refid = ip_set_get_byname(map->net,
nla_data(tb[IPSET_ATTR_NAMEREF]),
&s); &s);
if (e.refid == IPSET_INVALID_ID) { if (e.refid == IPSET_INVALID_ID) {
ret = -IPSET_ERR_NAMEREF; ret = -IPSET_ERR_NAMEREF;
...@@ -421,9 +424,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -421,9 +424,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
finish: finish:
if (e.refid != IPSET_INVALID_ID) if (e.refid != IPSET_INVALID_ID)
ip_set_put_byindex(e.refid); ip_set_put_byindex(map->net, e.refid);
if (adt != IPSET_ADD || ret) if (adt != IPSET_ADD || ret)
ip_set_put_byindex(e.id); ip_set_put_byindex(map->net, e.id);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -438,7 +441,7 @@ list_set_flush(struct ip_set *set) ...@@ -438,7 +441,7 @@ list_set_flush(struct ip_set *set)
for (i = 0; i < map->size; i++) { for (i = 0; i < map->size; i++) {
e = list_set_elem(set, map, i); e = list_set_elem(set, map, i);
if (e->id != IPSET_INVALID_ID) { if (e->id != IPSET_INVALID_ID) {
ip_set_put_byindex(e->id); ip_set_put_byindex(map->net, e->id);
ip_set_ext_destroy(set, e); ip_set_ext_destroy(set, e);
e->id = IPSET_INVALID_ID; e->id = IPSET_INVALID_ID;
} }
...@@ -510,7 +513,7 @@ list_set_list(const struct ip_set *set, ...@@ -510,7 +513,7 @@ list_set_list(const struct ip_set *set,
goto nla_put_failure; goto nla_put_failure;
} }
if (nla_put_string(skb, IPSET_ATTR_NAME, if (nla_put_string(skb, IPSET_ATTR_NAME,
ip_set_name_byindex(e->id))) ip_set_name_byindex(map->net, e->id)))
goto nla_put_failure; goto nla_put_failure;
if (ip_set_put_extensions(skb, set, e, true)) if (ip_set_put_extensions(skb, set, e, true))
goto nla_put_failure; goto nla_put_failure;
...@@ -587,7 +590,7 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) ...@@ -587,7 +590,7 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
/* Create list:set type of sets */ /* Create list:set type of sets */
static bool static bool
init_list_set(struct ip_set *set, u32 size) init_list_set(struct net *net, struct ip_set *set, u32 size)
{ {
struct list_set *map; struct list_set *map;
struct set_elem *e; struct set_elem *e;
...@@ -598,6 +601,7 @@ init_list_set(struct ip_set *set, u32 size) ...@@ -598,6 +601,7 @@ init_list_set(struct ip_set *set, u32 size)
return false; return false;
map->size = size; map->size = size;
map->net = net;
set->data = map; set->data = map;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
...@@ -609,7 +613,8 @@ init_list_set(struct ip_set *set, u32 size) ...@@ -609,7 +613,8 @@ init_list_set(struct ip_set *set, u32 size)
} }
static int static int
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
u32 flags)
{ {
u32 size = IP_SET_LIST_DEFAULT_SIZE; u32 size = IP_SET_LIST_DEFAULT_SIZE;
...@@ -625,7 +630,7 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -625,7 +630,7 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
set->variant = &set_variant; set->variant = &set_variant;
set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem)); set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
if (!init_list_set(set, size)) if (!init_list_set(net, set, size))
return -ENOMEM; return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
......
...@@ -81,7 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) ...@@ -81,7 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
struct xt_set_info_match_v0 *info = par->matchinfo; struct xt_set_info_match_v0 *info = par->matchinfo;
ip_set_id_t index; ip_set_id_t index;
index = ip_set_nfnl_get_byindex(info->match_set.index); index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n", pr_warning("Cannot find set indentified by id %u to match\n",
...@@ -91,7 +91,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) ...@@ -91,7 +91,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("Protocol error: set match dimension " pr_warning("Protocol error: set match dimension "
"is over the limit!\n"); "is over the limit!\n");
ip_set_nfnl_put(info->match_set.index); ip_set_nfnl_put(par->net, info->match_set.index);
return -ERANGE; return -ERANGE;
} }
...@@ -106,7 +106,7 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par) ...@@ -106,7 +106,7 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
{ {
struct xt_set_info_match_v0 *info = par->matchinfo; struct xt_set_info_match_v0 *info = par->matchinfo;
ip_set_nfnl_put(info->match_set.index); ip_set_nfnl_put(par->net, info->match_set.index);
} }
/* Revision 1 match */ /* Revision 1 match */
...@@ -131,7 +131,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par) ...@@ -131,7 +131,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
struct xt_set_info_match_v1 *info = par->matchinfo; struct xt_set_info_match_v1 *info = par->matchinfo;
ip_set_id_t index; ip_set_id_t index;
index = ip_set_nfnl_get_byindex(info->match_set.index); index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n", pr_warning("Cannot find set indentified by id %u to match\n",
...@@ -141,7 +141,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par) ...@@ -141,7 +141,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
if (info->match_set.dim > IPSET_DIM_MAX) { if (info->match_set.dim > IPSET_DIM_MAX) {
pr_warning("Protocol error: set match dimension " pr_warning("Protocol error: set match dimension "
"is over the limit!\n"); "is over the limit!\n");
ip_set_nfnl_put(info->match_set.index); ip_set_nfnl_put(par->net, info->match_set.index);
return -ERANGE; return -ERANGE;
} }
...@@ -153,7 +153,7 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par) ...@@ -153,7 +153,7 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par)
{ {
struct xt_set_info_match_v1 *info = par->matchinfo; struct xt_set_info_match_v1 *info = par->matchinfo;
ip_set_nfnl_put(info->match_set.index); ip_set_nfnl_put(par->net, info->match_set.index);
} }
/* Revision 3 match */ /* Revision 3 match */
...@@ -228,7 +228,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) ...@@ -228,7 +228,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
ip_set_id_t index; ip_set_id_t index;
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n", pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index); info->add_set.index);
...@@ -237,12 +237,12 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) ...@@ -237,12 +237,12 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
} }
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n", pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index); info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
return -ENOENT; return -ENOENT;
} }
} }
...@@ -251,9 +251,9 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) ...@@ -251,9 +251,9 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
pr_warning("Protocol error: SET target dimension " pr_warning("Protocol error: SET target dimension "
"is over the limit!\n"); "is over the limit!\n");
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID) if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index); ip_set_nfnl_put(par->net, info->del_set.index);
return -ERANGE; return -ERANGE;
} }
...@@ -270,9 +270,9 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par) ...@@ -270,9 +270,9 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
const struct xt_set_info_target_v0 *info = par->targinfo; const struct xt_set_info_target_v0 *info = par->targinfo;
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID) if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index); ip_set_nfnl_put(par->net, info->del_set.index);
} }
/* Revision 1 target */ /* Revision 1 target */
...@@ -301,7 +301,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) ...@@ -301,7 +301,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
ip_set_id_t index; ip_set_id_t index;
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n", pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index); info->add_set.index);
...@@ -310,12 +310,12 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) ...@@ -310,12 +310,12 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
} }
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n", pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index); info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
return -ENOENT; return -ENOENT;
} }
} }
...@@ -324,9 +324,9 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) ...@@ -324,9 +324,9 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
pr_warning("Protocol error: SET target dimension " pr_warning("Protocol error: SET target dimension "
"is over the limit!\n"); "is over the limit!\n");
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID) if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index); ip_set_nfnl_put(par->net, info->del_set.index);
return -ERANGE; return -ERANGE;
} }
...@@ -339,9 +339,9 @@ set_target_v1_destroy(const struct xt_tgdtor_param *par) ...@@ -339,9 +339,9 @@ set_target_v1_destroy(const struct xt_tgdtor_param *par)
const struct xt_set_info_target_v1 *info = par->targinfo; const struct xt_set_info_target_v1 *info = par->targinfo;
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index); ip_set_nfnl_put(par->net, info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID) if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index); ip_set_nfnl_put(par->net, info->del_set.index);
} }
/* Revision 2 target */ /* Revision 2 target */
......
...@@ -24,11 +24,12 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, ...@@ -24,11 +24,12 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len,
{ {
struct xt_set_info *set = data; struct xt_set_info *set = data;
ip_set_id_t index; ip_set_id_t index;
struct net *net = qdisc_dev(tp->q)->nd_net;
if (data_len != sizeof(*set)) if (data_len != sizeof(*set))
return -EINVAL; return -EINVAL;
index = ip_set_nfnl_get_byindex(set->index); index = ip_set_nfnl_get_byindex(net, set->index);
if (index == IPSET_INVALID_ID) if (index == IPSET_INVALID_ID)
return -ENOENT; return -ENOENT;
...@@ -37,7 +38,7 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, ...@@ -37,7 +38,7 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len,
if (em->data) if (em->data)
return 0; return 0;
ip_set_nfnl_put(index); ip_set_nfnl_put(net, index);
return -ENOMEM; return -ENOMEM;
} }
...@@ -45,7 +46,7 @@ static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em) ...@@ -45,7 +46,7 @@ static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em)
{ {
const struct xt_set_info *set = (const void *) em->data; const struct xt_set_info *set = (const void *) em->data;
if (set) { if (set) {
ip_set_nfnl_put(set->index); ip_set_nfnl_put(qdisc_dev(p->q)->nd_net, set->index);
kfree((void *) em->data); kfree((void *) em->data);
} }
} }
......
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