mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-12-26 18:03:55 +01:00
ipset: update to ipset-6.2
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
|
||||
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_RWLOCK(ip_set_ref_lock); /* protects the set refs */
|
||||
|
||||
static struct ip_set **ip_set_list; /* all individual sets */
|
||||
static ip_set_id_t ip_set_max = LCONFIG_IP_SET_MAX; /* max number of sets */
|
||||
@@ -97,16 +98,28 @@ static int
|
||||
find_set_type_get(const char *name, u8 family, u8 revision,
|
||||
struct ip_set_type **found)
|
||||
{
|
||||
struct ip_set_type *type;
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
*found = find_set_type(name, family, revision);
|
||||
if (*found) {
|
||||
int err = !try_module_get((*found)->me);
|
||||
rcu_read_unlock();
|
||||
return err ? -EFAULT : 0;
|
||||
err = !try_module_get((*found)->me) ? -EFAULT : 0;
|
||||
goto unlock;
|
||||
}
|
||||
/* Make sure the type is loaded but we don't support the revision */
|
||||
list_for_each_entry_rcu(type, &ip_set_type_list, list)
|
||||
if (STREQ(type->name, name)) {
|
||||
err = -IPSET_ERR_FIND_TYPE;
|
||||
goto unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return try_to_load_type(name);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Find a given set type by name and family.
|
||||
@@ -119,7 +132,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
|
||||
struct ip_set_type *type;
|
||||
bool found = false;
|
||||
|
||||
*min = *max = 0;
|
||||
*min = 255; *max = 0;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(type, &ip_set_type_list, list)
|
||||
if (STREQ(type->name, name) &&
|
||||
@@ -127,7 +140,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
|
||||
found = true;
|
||||
if (type->revision < *min)
|
||||
*min = type->revision;
|
||||
else if (type->revision > *max)
|
||||
if (type->revision > *max)
|
||||
*max = type->revision;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@@ -297,13 +310,18 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
|
||||
static inline void
|
||||
__ip_set_get(ip_set_id_t index)
|
||||
{
|
||||
atomic_inc(&ip_set_list[index]->ref);
|
||||
write_lock_bh(&ip_set_ref_lock);
|
||||
ip_set_list[index]->ref++;
|
||||
write_unlock_bh(&ip_set_ref_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__ip_set_put(ip_set_id_t index)
|
||||
{
|
||||
atomic_dec(&ip_set_list[index]->ref);
|
||||
write_lock_bh(&ip_set_ref_lock);
|
||||
BUG_ON(ip_set_list[index]->ref == 0);
|
||||
ip_set_list[index]->ref--;
|
||||
write_unlock_bh(&ip_set_ref_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -320,7 +338,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
@@ -352,7 +370,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret;
|
||||
|
||||
BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
@@ -374,7 +392,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
@@ -393,7 +411,6 @@ EXPORT_SYMBOL_GPL(ip_set_del);
|
||||
* Find set by name, reference it once. The reference makes sure the
|
||||
* thing pointed to, does not go away under our feet.
|
||||
*
|
||||
* The nfnl mutex must already be activated.
|
||||
*/
|
||||
ip_set_id_t
|
||||
ip_set_get_byname(const char *name, struct ip_set **set)
|
||||
@@ -419,15 +436,12 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
|
||||
* reference count by 1. The caller shall not assume the index
|
||||
* to be valid, after calling this function.
|
||||
*
|
||||
* The nfnl mutex must already be activated.
|
||||
*/
|
||||
void
|
||||
ip_set_put_byindex(ip_set_id_t index)
|
||||
{
|
||||
if (ip_set_list[index] != NULL) {
|
||||
BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
|
||||
if (ip_set_list[index] != NULL)
|
||||
__ip_set_put(index);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_put_byindex);
|
||||
|
||||
@@ -437,7 +451,6 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
|
||||
* can't be destroyed. The set cannot be renamed due to
|
||||
* the referencing either.
|
||||
*
|
||||
* The nfnl mutex must already be activated.
|
||||
*/
|
||||
const char *
|
||||
ip_set_name_byindex(ip_set_id_t index)
|
||||
@@ -445,7 +458,7 @@ ip_set_name_byindex(ip_set_id_t index)
|
||||
const struct ip_set *set = ip_set_list[index];
|
||||
|
||||
BUG_ON(set == NULL);
|
||||
BUG_ON(atomic_read(&set->ref) == 0);
|
||||
BUG_ON(set->ref == 0);
|
||||
|
||||
/* Referenced, so it's safe */
|
||||
return set->name;
|
||||
@@ -511,10 +524,7 @@ void
|
||||
ip_set_nfnl_put(ip_set_id_t index)
|
||||
{
|
||||
nfnl_lock();
|
||||
if (ip_set_list[index] != NULL) {
|
||||
BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
|
||||
__ip_set_put(index);
|
||||
}
|
||||
ip_set_put_byindex(index);
|
||||
nfnl_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
|
||||
@@ -522,7 +532,7 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
|
||||
/*
|
||||
* Communication protocol with userspace over netlink.
|
||||
*
|
||||
* We already locked by nfnl_lock.
|
||||
* The commands are serialized by the nfnl mutex.
|
||||
*/
|
||||
|
||||
static inline bool
|
||||
@@ -611,8 +621,7 @@ static int
|
||||
ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *const *attr = info->attrs;
|
||||
|
||||
struct ip_set *set, *clash;
|
||||
struct ip_set *set, *clash = NULL;
|
||||
ip_set_id_t index = IPSET_INVALID_ID;
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
const char *name, *typename;
|
||||
@@ -645,7 +654,6 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
return -ENOMEM;
|
||||
rwlock_init(&set->lock);
|
||||
strlcpy(set->name, name, IPSET_MAXNAMELEN);
|
||||
atomic_set(&set->ref, 0);
|
||||
set->family = family;
|
||||
|
||||
/*
|
||||
@@ -678,8 +686,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
/*
|
||||
* Here, we have a valid, constructed set and we are protected
|
||||
* by nfnl_lock. Find the first free index in ip_set_list and
|
||||
* check clashing.
|
||||
* by the nfnl mutex. Find the first free index in ip_set_list
|
||||
* and check clashing.
|
||||
*/
|
||||
if ((ret = find_free_id(set->name, &index, &clash)) != 0) {
|
||||
/* If this is the same set and requested, ignore error */
|
||||
@@ -738,31 +746,51 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr *const *attr = info->attrs;
|
||||
ip_set_id_t i;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(protocol_failed(attr)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
/* References are protected by the nfnl mutex */
|
||||
/* Commands are serialized and references are
|
||||
* protected by the ip_set_ref_lock.
|
||||
* External systems (i.e. xt_set) must call
|
||||
* ip_set_put|get_nfnl_* functions, that way we
|
||||
* can safely check references here.
|
||||
*
|
||||
* list:set timer can only decrement the reference
|
||||
* counter, so if it's already zero, we can proceed
|
||||
* without holding the lock.
|
||||
*/
|
||||
read_lock_bh(&ip_set_ref_lock);
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
if (ip_set_list[i] != NULL &&
|
||||
(atomic_read(&ip_set_list[i]->ref)))
|
||||
return -IPSET_ERR_BUSY;
|
||||
if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
|
||||
ret = IPSET_ERR_BUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
if (ip_set_list[i] != NULL)
|
||||
ip_set_destroy_set(i);
|
||||
}
|
||||
} else {
|
||||
i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (i == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
else if (atomic_read(&ip_set_list[i]->ref))
|
||||
return -IPSET_ERR_BUSY;
|
||||
if (i == IPSET_INVALID_ID) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
} else if (ip_set_list[i]->ref) {
|
||||
ret = -IPSET_ERR_BUSY;
|
||||
goto out;
|
||||
}
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
|
||||
ip_set_destroy_set(i);
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Flush sets */
|
||||
@@ -819,6 +847,7 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
|
||||
struct ip_set *set;
|
||||
const char *name2;
|
||||
ip_set_id_t i;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(protocol_failed(attr) ||
|
||||
attr[IPSET_ATTR_SETNAME] == NULL ||
|
||||
@@ -828,25 +857,33 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
if (atomic_read(&set->ref) != 0)
|
||||
return -IPSET_ERR_REFERENCED;
|
||||
|
||||
read_lock_bh(&ip_set_ref_lock);
|
||||
if (set->ref != 0) {
|
||||
ret = -IPSET_ERR_REFERENCED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
if (ip_set_list[i] != NULL &&
|
||||
STREQ(ip_set_list[i]->name, name2))
|
||||
return -IPSET_ERR_EXIST_SETNAME2;
|
||||
STREQ(ip_set_list[i]->name, name2)) {
|
||||
ret = -IPSET_ERR_EXIST_SETNAME2;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
strncpy(set->name, name2, IPSET_MAXNAMELEN);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Swap two sets so that name/index points to the other.
|
||||
* References and set names are also swapped.
|
||||
*
|
||||
* We are protected by the nfnl mutex and references are
|
||||
* manipulated only by holding the mutex. The kernel interfaces
|
||||
* The commands are serialized by the nfnl mutex and references are
|
||||
* protected by the ip_set_ref_lock. The kernel interfaces
|
||||
* do not hold the mutex but the pointer settings are atomic
|
||||
* so the ip_set_list always contains valid pointers to the sets.
|
||||
*/
|
||||
@@ -858,7 +895,6 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
|
||||
struct ip_set *from, *to;
|
||||
ip_set_id_t from_id, to_id;
|
||||
char from_name[IPSET_MAXNAMELEN];
|
||||
u32 from_ref;
|
||||
|
||||
if (unlikely(protocol_failed(attr) ||
|
||||
attr[IPSET_ATTR_SETNAME] == NULL ||
|
||||
@@ -883,17 +919,15 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
|
||||
from->type->family == to->type->family))
|
||||
return -IPSET_ERR_TYPE_MISMATCH;
|
||||
|
||||
/* No magic here: ref munging protected by the nfnl_lock */
|
||||
strncpy(from_name, from->name, IPSET_MAXNAMELEN);
|
||||
from_ref = atomic_read(&from->ref);
|
||||
|
||||
strncpy(from->name, to->name, IPSET_MAXNAMELEN);
|
||||
atomic_set(&from->ref, atomic_read(&to->ref));
|
||||
strncpy(to->name, from_name, IPSET_MAXNAMELEN);
|
||||
atomic_set(&to->ref, from_ref);
|
||||
|
||||
write_lock_bh(&ip_set_ref_lock);
|
||||
swap(from->ref, to->ref);
|
||||
ip_set_list[from_id] = to;
|
||||
ip_set_list[to_id] = from;
|
||||
write_unlock_bh(&ip_set_ref_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -910,7 +944,7 @@ ip_set_dump_done(struct netlink_callback *cb)
|
||||
{
|
||||
if (cb->args[2]) {
|
||||
pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name);
|
||||
__ip_set_put((ip_set_id_t) cb->args[1]);
|
||||
ip_set_put_byindex((ip_set_id_t) cb->args[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1053,7 +1087,7 @@ release_refcount:
|
||||
/* If there was an error or set is done, release set */
|
||||
if (ret || !cb->args[2]) {
|
||||
pr_debug("release set %s\n", ip_set_list[index]->name);
|
||||
__ip_set_put(index);
|
||||
ip_set_put_byindex(index);
|
||||
}
|
||||
|
||||
/* If we dump all sets, continue with dumping last ones */
|
||||
|
||||
Reference in New Issue
Block a user