Commit f1e00b39 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Patrick McHardy

netfilter: ipset: set type support with multiple revisions added

A set type may have multiple revisions, for example when syntax is
extended. Support continuous revision ranges in set types.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent 3d14b171
...@@ -282,8 +282,8 @@ struct ip_set_type { ...@@ -282,8 +282,8 @@ struct ip_set_type {
u8 dimension; u8 dimension;
/* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
u8 family; u8 family;
/* Type revision */ /* Type revisions */
u8 revision; u8 revision_min, revision_max;
/* Create set */ /* Create set */
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
...@@ -314,6 +314,8 @@ struct ip_set { ...@@ -314,6 +314,8 @@ struct ip_set {
const struct ip_set_type_variant *variant; const struct ip_set_type_variant *variant;
/* The actual INET family of the set */ /* The actual INET family of the set */
u8 family; u8 family;
/* The type revision */
u8 revision;
/* The type specific data */ /* The type specific data */
void *data; void *data;
}; };
......
...@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { ...@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_INET, .family = AF_INET,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = bitmap_ip_create, .create = bitmap_ip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
......
...@@ -623,7 +623,8 @@ static struct ip_set_type bitmap_ipmac_type = { ...@@ -623,7 +623,8 @@ static struct ip_set_type bitmap_ipmac_type = {
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC, .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_INET, .family = AF_INET,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = bitmap_ipmac_create, .create = bitmap_ipmac_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
......
...@@ -483,7 +483,8 @@ static struct ip_set_type bitmap_port_type = { ...@@ -483,7 +483,8 @@ static struct ip_set_type bitmap_port_type = {
.features = IPSET_TYPE_PORT, .features = IPSET_TYPE_PORT,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = bitmap_port_create, .create = bitmap_port_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_PORT] = { .type = NLA_U16 },
......
...@@ -70,7 +70,8 @@ find_set_type(const char *name, u8 family, u8 revision) ...@@ -70,7 +70,8 @@ find_set_type(const char *name, u8 family, u8 revision)
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC) && (type->family == family || type->family == AF_UNSPEC) &&
type->revision == revision) revision >= type->revision_min &&
revision <= type->revision_max)
return type; return type;
return NULL; return NULL;
} }
...@@ -135,10 +136,10 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) ...@@ -135,10 +136,10 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC)) { (type->family == family || type->family == AF_UNSPEC)) {
found = true; found = true;
if (type->revision < *min) if (type->revision_min < *min)
*min = type->revision; *min = type->revision_min;
if (type->revision > *max) if (type->revision_max > *max)
*max = type->revision; *max = type->revision_max;
} }
rcu_read_unlock(); rcu_read_unlock();
if (found) if (found)
...@@ -159,25 +160,27 @@ ip_set_type_register(struct ip_set_type *type) ...@@ -159,25 +160,27 @@ ip_set_type_register(struct ip_set_type *type)
int ret = 0; int ret = 0;
if (type->protocol != IPSET_PROTOCOL) { 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", "wrong protocol version %u (want %u)\n",
type->name, family_name(type->family), type->name, family_name(type->family),
type->revision, type->protocol, IPSET_PROTOCOL); type->revision_min, type->revision_max,
type->protocol, IPSET_PROTOCOL);
return -EINVAL; return -EINVAL;
} }
ip_set_type_lock(); 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! */ /* 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, "already registered!\n", type->name,
family_name(type->family), type->revision); family_name(type->family), type->revision_min);
ret = -EINVAL; ret = -EINVAL;
goto unlock; goto unlock;
} }
list_add_rcu(&type->list, &ip_set_type_list); list_add_rcu(&type->list, &ip_set_type_list);
pr_debug("type %s, family %s, revision %u registered.\n", pr_debug("type %s, family %s, revision %u:%u registered.\n",
type->name, family_name(type->family), type->revision); type->name, family_name(type->family),
type->revision_min, type->revision_max);
unlock: unlock:
ip_set_type_unlock(); ip_set_type_unlock();
return ret; return ret;
...@@ -189,15 +192,15 @@ void ...@@ -189,15 +192,15 @@ void
ip_set_type_unregister(struct ip_set_type *type) ip_set_type_unregister(struct ip_set_type *type)
{ {
ip_set_type_lock(); 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)) {
pr_warning("ip_set type %s, family %s, revision %u " pr_warning("ip_set type %s, family %s with revision min %u "
"not registered\n", type->name, "not registered\n", type->name,
family_name(type->family), type->revision); family_name(type->family), type->revision_min);
goto unlock; goto unlock;
} }
list_del_rcu(&type->list); list_del_rcu(&type->list);
pr_debug("type %s, family %s, revision %u unregistered.\n", pr_debug("type %s, family %s with revision min %u unregistered.\n",
type->name, family_name(type->family), type->revision); type->name, family_name(type->family), type->revision_min);
unlock: unlock:
ip_set_type_unlock(); ip_set_type_unlock();
...@@ -656,6 +659,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -656,6 +659,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
rwlock_init(&set->lock); rwlock_init(&set->lock);
strlcpy(set->name, name, IPSET_MAXNAMELEN); strlcpy(set->name, name, IPSET_MAXNAMELEN);
set->family = family; set->family = family;
set->revision = revision;
/* /*
* Next, check that we know the type, and take * Next, check that we know the type, and take
...@@ -696,7 +700,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -696,7 +700,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
(flags & IPSET_FLAG_EXIST) && (flags & IPSET_FLAG_EXIST) &&
STREQ(set->type->name, clash->type->name) && STREQ(set->type->name, clash->type->name) &&
set->type->family == clash->type->family && 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)) set->variant->same_set(set, clash))
ret = 0; ret = 0;
goto cleanup; goto cleanup;
...@@ -1080,7 +1085,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1080,7 +1085,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
NLA_PUT_U8(skb, IPSET_ATTR_FAMILY, NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
set->family); set->family);
NLA_PUT_U8(skb, IPSET_ATTR_REVISION, NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
set->type->revision); set->revision);
ret = set->variant->head(set, skb); ret = set->variant->head(set, skb);
if (ret < 0) if (ret < 0)
goto release_refcount; goto release_refcount;
...@@ -1385,7 +1390,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb, ...@@ -1385,7 +1390,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name); NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->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_FAMILY, set->family);
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision); NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
......
...@@ -441,7 +441,8 @@ static struct ip_set_type hash_ip_type __read_mostly = { ...@@ -441,7 +441,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = hash_ip_create, .create = hash_ip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -512,7 +512,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = { ...@@ -512,7 +512,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 1, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipport_create, .create = hash_ipport_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -530,7 +530,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { ...@@ -530,7 +530,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE, .dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 1, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipportip_create, .create = hash_ipportip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -595,7 +595,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { ...@@ -595,7 +595,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE, .dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 1, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipportnet_create, .create = hash_ipportnet_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -437,7 +437,8 @@ static struct ip_set_type hash_net_type __read_mostly = { ...@@ -437,7 +437,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = hash_net_create, .create = hash_net_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -544,7 +544,8 @@ static struct ip_set_type hash_netport_type __read_mostly = { ...@@ -544,7 +544,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 1, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_netport_create, .create = hash_netport_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -575,7 +575,8 @@ static struct ip_set_type list_set_type __read_mostly = { ...@@ -575,7 +575,8 @@ static struct ip_set_type list_set_type __read_mostly = {
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision_min = 0,
.revision_max = 0,
.create = list_set_create, .create = list_set_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_SIZE] = { .type = NLA_U32 }, [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
......
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