ipset: update to 6.6a-genl

This commit is contained in:
Jan Engelhardt
2011-05-31 16:14:44 +02:00
parent 1b0790d151
commit cfb72bf468
43 changed files with 1488 additions and 1720 deletions

View File

@@ -21,6 +21,7 @@
#include <net/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include "ip_set.h"
#include <net/genetlink.h>
@@ -75,7 +76,8 @@ find_set_type(const char *name, u8 family, u8 revision)
list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC) &&
type->revision == revision)
revision >= type->revision_min &&
revision <= type->revision_max)
return type;
return NULL;
}
@@ -148,10 +150,10 @@ retry:
if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC)) {
found = true;
if (type->revision < *min)
*min = type->revision;
if (type->revision > *max)
*max = type->revision;
if (type->revision_min < *min)
*min = type->revision_min;
if (type->revision_max > *max)
*max = type->revision_max;
}
rcu_read_unlock();
if (found)
@@ -175,25 +177,27 @@ ip_set_type_register(struct ip_set_type *type)
int ret = 0;
if (type->protocol != IPSET_PROTOCOL) {
pr_warning("ip_set type %s, family %s, revision %u uses "
pr_warning("ip_set type %s, family %s, revision %u:%u uses "
"wrong protocol version %u (want %u)\n",
type->name, family_name(type->family),
type->revision, type->protocol, IPSET_PROTOCOL);
type->revision_min, type->revision_max,
type->protocol, IPSET_PROTOCOL);
return -EINVAL;
}
ip_set_type_lock();
if (find_set_type(type->name, type->family, type->revision)) {
if (find_set_type(type->name, type->family, type->revision_min)) {
/* Duplicate! */
pr_warning("ip_set type %s, family %s, revision %u "
pr_warning("ip_set type %s, family %s with revision min %u "
"already registered!\n", type->name,
family_name(type->family), type->revision);
family_name(type->family), type->revision_min);
ret = -EINVAL;
goto unlock;
}
list_add_rcu(&type->list, &ip_set_type_list);
pr_debug("type %s, family %s, revision %u registered.\n",
type->name, family_name(type->family), type->revision);
pr_debug("type %s, family %s, revision %u:%u registered.\n",
type->name, family_name(type->family),
type->revision_min, type->revision_max);
unlock:
ip_set_type_unlock();
return ret;
@@ -205,15 +209,15 @@ void
ip_set_type_unregister(struct ip_set_type *type)
{
ip_set_type_lock();
if (!find_set_type(type->name, type->family, type->revision)) {
pr_warning("ip_set type %s, family %s, revision %u "
if (!find_set_type(type->name, type->family, type->revision_min)) {
pr_warning("ip_set type %s, family %s with revision min %u "
"not registered\n", type->name,
family_name(type->family), type->revision);
family_name(type->family), type->revision_min);
goto unlock;
}
list_del_rcu(&type->list);
pr_debug("type %s, family %s, revision %u unregistered.\n",
type->name, family_name(type->family), type->revision);
pr_debug("type %s, family %s with revision min %u unregistered.\n",
type->name, family_name(type->family), type->revision_min);
unlock:
ip_set_type_unlock();
@@ -346,7 +350,8 @@ __ip_set_put(ip_set_id_t index)
int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret = 0;
@@ -354,19 +359,19 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
read_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
read_unlock_bh(&set->lock);
if (ret == -EAGAIN) {
/* Type requests element to be completed */
pr_debug("element must be competed, ADD is triggered\n");
write_lock_bh(&set->lock);
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
set->variant->kadt(set, skb, par, IPSET_ADD, opt);
write_unlock_bh(&set->lock);
ret = 1;
}
@@ -378,7 +383,8 @@ EXPORT_SYMBOL_GPL(ip_set_test);
int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret;
@@ -386,12 +392,12 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
write_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
write_unlock_bh(&set->lock);
return ret;
@@ -400,7 +406,8 @@ EXPORT_SYMBOL_GPL(ip_set_add);
int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret = 0;
@@ -408,12 +415,12 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
write_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
write_unlock_bh(&set->lock);
return ret;
@@ -668,6 +675,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
rwlock_init(&set->lock);
strlcpy(set->name, name, IPSET_MAXNAMELEN);
set->family = family;
set->revision = revision;
/*
* Next, check that we know the type, and take
@@ -708,7 +716,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
(flags & IPSET_FLAG_EXIST) &&
STREQ(set->type->name, clash->type->name) &&
set->type->family == clash->type->family &&
set->type->revision == clash->type->revision &&
set->type->revision_min == clash->type->revision_min &&
set->type->revision_max == clash->type->revision_max &&
set->variant->same_set(set, clash))
ret = 0;
goto cleanup;
@@ -778,7 +787,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
ret = IPSET_ERR_BUSY;
ret = -IPSET_ERR_BUSY;
goto out;
}
}
@@ -825,7 +834,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
ip_set_id_t i;
if (unlikely(protocol_failed(attr)))
return -EPROTO;
return -IPSET_ERR_PROTOCOL;
if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++)
@@ -947,10 +956,13 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
/* List/save set data */
#define DUMP_INIT 0L
#define DUMP_ALL 1L
#define DUMP_ONE 2L
#define DUMP_LAST 3L
#define DUMP_INIT 0
#define DUMP_ALL 1
#define DUMP_ONE 2
#define DUMP_LAST 3
#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
static int
ip_set_dump_done(struct netlink_callback *cb)
@@ -983,6 +995,7 @@ dump_init(struct netlink_callback *cb)
int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *attr = (void *)nlh + min_len;
u32 dump_type;
ip_set_id_t index;
/* Second pass, so parser can't fail */
@@ -994,17 +1007,22 @@ dump_init(struct netlink_callback *cb)
* [..]: type specific
*/
if (!cda[IPSET_ATTR_SETNAME]) {
cb->args[0] = DUMP_ALL;
return 0;
if (cda[IPSET_ATTR_SETNAME]) {
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID)
return -ENOENT;
dump_type = DUMP_ONE;
cb->args[1] = index;
} else
dump_type = DUMP_ALL;
if (cda[IPSET_ATTR_FLAGS]) {
u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
dump_type |= (f << 16);
}
cb->args[0] = dump_type;
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID)
return -ENOENT;
cb->args[0] = DUMP_ONE;
cb->args[1] = index;
return 0;
}
@@ -1015,9 +1033,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_set *set = NULL;
struct genlmsg_buf *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
u32 dump_type, dump_flags;
int ret = 0;
if (cb->args[0] == DUMP_INIT) {
if (!cb->args[0]) {
ret = dump_init(cb);
if (ret < 0) {
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
@@ -1032,13 +1051,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->args[1] >= ip_set_max)
goto out;
pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_type = DUMP_TYPE(cb->args[0]);
dump_flags = DUMP_FLAGS(cb->args[0]);
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_last:
pr_debug("args[0]: %u %u args[1]: %ld\n",
dump_type, dump_flags, cb->args[1]);
for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1];
set = ip_set_list[index];
if (set == NULL) {
if (cb->args[0] == DUMP_ONE) {
if (dump_type == DUMP_ONE) {
ret = -ENOENT;
goto out;
}
@@ -1047,9 +1070,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
/* When dumping all sets, we must dump "sorted"
* so that lists (unions of sets) are dumped last.
*/
if (cb->args[0] != DUMP_ONE &&
!((cb->args[0] == DUMP_ALL) ^
(set->type->features & IPSET_DUMP_LAST)))
if (dump_type != DUMP_ONE &&
((dump_type == DUMP_ALL) ==
!!(set->type->features & IPSET_DUMP_LAST)))
continue;
pr_debug("List set: %s\n", set->name);
if (!cb->args[2]) {
@@ -1066,6 +1089,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
}
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
goto next_set;
switch (cb->args[2]) {
case 0:
/* Core header data */
@@ -1074,40 +1099,45 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
set->family);
NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
set->type->revision);
set->revision);
ret = set->variant->head(set, skb);
if (ret < 0)
goto release_refcount;
if (dump_flags & IPSET_FLAG_LIST_HEADER)
goto next_set;
/* Fall through and add elements */
default:
read_lock_bh(&set->lock);
ret = set->variant->list(set, skb, cb);
read_unlock_bh(&set->lock);
if (!cb->args[2]) {
if (!cb->args[2])
/* Set is done, proceed with next one */
if (cb->args[0] == DUMP_ONE)
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
}
goto next_set;
goto release_refcount;
}
}
/* If we dump all sets, continue with dumping last ones */
if (dump_type == DUMP_ALL) {
dump_type = DUMP_LAST;
cb->args[0] = dump_type | (dump_flags << 16);
cb->args[1] = 0;
goto dump_last;
}
goto out;
nla_put_failure:
ret = -EFAULT;
next_set:
if (dump_type == DUMP_ONE)
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
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_byindex(index);
}
/* If we dump all sets, continue with dumping last ones */
if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
cb->args[0] = DUMP_LAST;
out:
if (nlh) {
genlmsg_end(skb, nlh);
@@ -1153,17 +1183,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
struct nlattr *tb[], enum ipset_adt adt,
u32 flags, bool use_lineno)
{
int ret, retried = 0;
int ret;
u32 lineno = 0;
bool eexist = flags & IPSET_FLAG_EXIST;
bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
do {
write_lock_bh(&set->lock);
ret = set->variant->uadt(set, tb, adt, &lineno, flags);
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
write_unlock_bh(&set->lock);
retried = true;
} while (ret == -EAGAIN &&
set->variant->resize &&
(ret = set->variant->resize(set, retried++)) == 0);
(ret = set->variant->resize(set, retried)) == 0);
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0;
@@ -1338,7 +1369,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
return -IPSET_ERR_PROTOCOL;
read_lock_bh(&set->lock);
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
read_unlock_bh(&set->lock);
/* Userspace can't trigger element to be re-added */
if (ret == -EAGAIN)
@@ -1381,7 +1412,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
genlmsg_end(skb2, nlh2);
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);