summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-03-27 21:01:33 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-03-27 21:01:33 +0200
commitbdd5135826516d4109922b0d8c61f8d200184f82 (patch)
treeb221fe881671679b14cd30bc26a9137ff7a69e62
parent29b83847687dcefe59b42056a80f1b0929efcd6e (diff)
Timeout can be modified for already added elements
When an element to a set with timeout added, one can change the timeout by "readding" the element with the "-exist" flag. That means the timeout value is reset to the specified one (or to the default from the set specification if the "timeout n" option is not used). Example ipset add foo 1.2.3.4 timeout 10 ipset add foo 1.2.3.4 timeout 600 -exist
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set.h3
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set_ahash.h15
-rw-r--r--kernel/net/netfilter/ipset/ip_set_bitmap_ip.c20
-rw-r--r--kernel/net/netfilter/ipset/ip_set_bitmap_ipmac.c21
-rw-r--r--kernel/net/netfilter/ipset/ip_set_bitmap_port.c20
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ip.c10
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ipport.c12
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ipportip.c12
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c12
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_net.c8
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_netport.c12
-rw-r--r--kernel/net/netfilter/ipset/ip_set_list_set.c92
-rw-r--r--tests/bitmap:ip.t10
-rw-r--r--tests/hash:ip.t8
-rw-r--r--tests/macipmap.t8
-rw-r--r--tests/portmap.t8
-rw-r--r--tests/setlist.t43
-rw-r--r--tests/setlist.t.before4
-rw-r--r--tests/setlist.t.list110
-rw-r--r--tests/setlist.t.list29
-rw-r--r--tests/setlist.t.list38
21 files changed, 244 insertions, 101 deletions
diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
index 5a262e3..277b7fb 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set.h
@@ -214,7 +214,8 @@ enum ip_set_feature {
struct ip_set;
-typedef int (*ipset_adtfn)(struct ip_set *set, void *value, u32 timeout);
+typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
+ u32 timeout, u32 flags);
/* Set type, variant-specific part */
struct ip_set_type_variant {
diff --git a/kernel/include/linux/netfilter/ipset/ip_set_ahash.h b/kernel/include/linux/netfilter/ipset/ip_set_ahash.h
index a0196ac..7ea9a60 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set_ahash.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set_ahash.h
@@ -349,7 +349,7 @@ retry:
/* Add an element to a hash and update the internal counters when succeeded,
* otherwise report the proper error code. */
static int
-type_pf_add(struct ip_set *set, void *value, u32 timeout)
+type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t;
@@ -388,7 +388,7 @@ out:
* and free up space if possible.
*/
static int
-type_pf_del(struct ip_set *set, void *value, u32 timeout)
+type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t = h->table;
@@ -463,7 +463,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
/* Test whether the element is added to the set */
static int
-type_pf_test(struct ip_set *set, void *value, u32 timeout)
+type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t = h->table;
@@ -776,7 +776,7 @@ retry:
}
static int
-type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
+type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t = h->table;
@@ -784,6 +784,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
struct hbucket *n;
struct type_pf_elem *data;
int ret = 0, i, j = AHASH_MAX_SIZE + 1;
+ bool flag_exist = flags & IPSET_FLAG_EXIST;
u32 key;
if (h->elements >= h->maxelem)
@@ -799,7 +800,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
for (i = 0; i < n->pos; i++) {
data = ahash_tdata(n, i);
if (type_pf_data_equal(data, d)) {
- if (type_pf_data_expired(data))
+ if (type_pf_data_expired(data) || flag_exist)
j = i;
else {
ret = -IPSET_ERR_EXIST;
@@ -833,7 +834,7 @@ out:
}
static int
-type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
+type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t = h->table;
@@ -905,7 +906,7 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
#endif
static int
-type_pf_ttest(struct ip_set *set, void *value, u32 timeout)
+type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct ip_set_hash *h = set->data;
struct htable *t = h->table;
diff --git a/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c b/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
index a113ff0..85b1cdf 100644
--- a/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/kernel/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -54,7 +54,7 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)
}
static int
-bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
@@ -63,7 +63,7 @@ bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
@@ -75,7 +75,7 @@ bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ip_del(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
@@ -131,7 +131,7 @@ nla_put_failure:
/* Timeout variant */
static int
-bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_ip *map = set->data;
const unsigned long *members = map->members;
@@ -141,13 +141,13 @@ bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ip *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
- if (ip_set_timeout_test(members[id]))
+ if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
return -IPSET_ERR_EXIST;
members[id] = ip_set_timeout_set(timeout);
@@ -156,7 +156,7 @@ bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout)
+bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ip *map = set->data;
unsigned long *members = map->members;
@@ -231,7 +231,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
ip = ip_to_id(map, ip);
- return adtfn(set, &ip, map->timeout);
+ return adtfn(set, &ip, map->timeout, flags);
}
static int
@@ -266,7 +266,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST) {
id = ip_to_id(map, ip);
- return adtfn(set, &id, timeout);
+ return adtfn(set, &id, timeout, flags);
}
if (tb[IPSET_ATTR_IP_TO]) {
@@ -293,7 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
for (; !before(ip_to, ip); ip += map->hosts) {
id = ip_to_id(map, ip);
- ret = adtfn(set, &id, timeout);;
+ ret = adtfn(set, &id, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/kernel/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 00a3324..35b4879 100644
--- a/kernel/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/kernel/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -99,7 +99,7 @@ bitmap_ipmac_exist(const struct ipmac_telem *elem)
/* Base variant */
static int
-bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
@@ -117,7 +117,7 @@ bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
@@ -146,7 +146,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
@@ -212,7 +212,7 @@ nla_put_failure:
/* Timeout variant */
static int
-bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
@@ -231,15 +231,16 @@ bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
+ bool flag_exist = flags & IPSET_FLAG_EXIST;
switch (elem->match) {
case MAC_UNSET:
- if (!data->ether)
+ if (!(data->ether || flag_exist))
/* Already added without ethernet address */
return -IPSET_ERR_EXIST;
/* Fill the MAC address and activate the timer */
@@ -251,7 +252,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
elem->timeout = ip_set_timeout_set(timeout);
break;
case MAC_FILLED:
- if (!bitmap_expired(map, data->id))
+ if (!(bitmap_expired(map, data->id) || flag_exist))
return -IPSET_ERR_EXIST;
/* Fall through */
case MAC_EMPTY:
@@ -273,7 +274,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout)
+bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_ipmac *map = set->data;
const struct ipmac *data = value;
@@ -355,7 +356,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
data.id -= map->first_ip;
data.ether = eth_hdr(skb)->h_source;
- return adtfn(set, &data, map->timeout);
+ return adtfn(set, &data, map->timeout, flags);
}
static int
@@ -395,7 +396,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
data.id -= map->first_ip;
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
diff --git a/kernel/net/netfilter/ipset/ip_set_bitmap_port.c b/kernel/net/netfilter/ipset/ip_set_bitmap_port.c
index 6b38eb8..a3935ee 100644
--- a/kernel/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/kernel/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -40,7 +40,7 @@ struct bitmap_port {
/* Base variant */
static int
-bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
@@ -49,7 +49,7 @@ bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
@@ -61,7 +61,7 @@ bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_port_del(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
@@ -119,7 +119,7 @@ nla_put_failure:
/* Timeout variant */
static int
-bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
const struct bitmap_port *map = set->data;
const unsigned long *members = map->members;
@@ -129,13 +129,13 @@ bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_port *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
- if (ip_set_timeout_test(members[id]))
+ if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
return -IPSET_ERR_EXIST;
members[id] = ip_set_timeout_set(timeout);
@@ -144,7 +144,7 @@ bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
}
static int
-bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout)
+bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
{
struct bitmap_port *map = set->data;
unsigned long *members = map->members;
@@ -225,7 +225,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
port -= map->first_port;
- return adtfn(set, &port, map->timeout);
+ return adtfn(set, &port, map->timeout, flags);
}
static int
@@ -259,7 +259,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST) {
id = port - map->first_port;
- return adtfn(set, &id, timeout);
+ return adtfn(set, &id, timeout, flags);
}
if (tb[IPSET_ATTR_PORT_TO]) {
@@ -277,7 +277,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
id = port - map->first_port;
- ret = adtfn(set, &id, timeout);
+ ret = adtfn(set, &id, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ip.c b/kernel/net/netfilter/ipset/ip_set_hash_ip.c
index 43bcce2..3683020 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ip.c
@@ -121,7 +121,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
if (ip == 0)
return -EINVAL;
- return adtfn(set, &ip, h->timeout);
+ return adtfn(set, &ip, h->timeout, flags);
}
static int
@@ -157,7 +157,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
nip = htonl(ip);
if (nip == 0)
return -IPSET_ERR_HASH_ELEM;
- return adtfn(set, &nip, timeout);
+ return adtfn(set, &nip, timeout, flags);
}
if (tb[IPSET_ATTR_IP_TO]) {
@@ -182,7 +182,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
nip = htonl(ip);
if (nip == 0)
return -IPSET_ERR_HASH_ELEM;
- ret = adtfn(set, &nip, timeout);
+ ret = adtfn(set, &nip, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -294,7 +294,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
if (ipv6_addr_any(&ip.in6))
return -EINVAL;
- return adtfn(set, &ip, h->timeout);
+ return adtfn(set, &ip, h->timeout, flags);
}
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
@@ -336,7 +336,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &ip, timeout);
+ ret = adtfn(set, &ip, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
index 14281b6..65c2ff4 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -138,7 +138,7 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -192,7 +192,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -224,7 +224,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
for (p = port; p <= port_to; p++) {
data.ip = htonl(ip);
data.port = htons(p);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -342,7 +342,7 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -396,7 +396,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -407,7 +407,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
data.port = htons(port);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c
index 401c8a2..670e5e4 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -142,7 +142,7 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -200,7 +200,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -232,7 +232,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
for (p = port; p <= port_to; p++) {
data.ip = htonl(ip);
data.port = htons(p);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -356,7 +356,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -414,7 +414,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -425,7 +425,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
data.port = htons(port);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 4743e54..4bb365c 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -162,7 +162,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
data.ip2 &= ip_set_netmask(data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -228,7 +228,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
for (p = port; p <= port_to; p++) {
data.ip = htonl(ip);
data.port = htons(p);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -410,7 +410,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
ip6_netmask(&data.ip2, data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -476,7 +476,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -487,7 +487,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
data.port = htons(port);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c
index c4db202..440b38f 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_net.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c
@@ -141,7 +141,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= ip_set_netmask(data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -179,7 +179,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -306,7 +306,7 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6_netmask(&data.ip, data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -344,7 +344,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netport.c b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
index d2a4036..2d31291 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
@@ -158,7 +158,7 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= ip_set_netmask(data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -216,7 +216,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -227,7 +227,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
data.port = htons(port);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -371,7 +371,7 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6_netmask(&data.ip, data.cidr);
- return adtfn(set, &data, h->timeout);
+ return adtfn(set, &data, h->timeout, flags);
}
static int
@@ -429,7 +429,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -440,7 +440,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
for (; port <= port_to; port++) {
data.port = htons(port);
- ret = adtfn(set, &data, timeout);
+ ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
diff --git a/kernel/net/netfilter/ipset/ip_set_list_set.c b/kernel/net/netfilter/ipset/ip_set_list_set.c
index e9159e9..a0290ff 100644
--- a/kernel/net/netfilter/ipset/ip_set_list_set.c
+++ b/kernel/net/netfilter/ipset/ip_set_list_set.c
@@ -109,15 +109,28 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
}
static bool
-next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
+id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
{
const struct set_elem *elem;
- if (i + 1 < map->size) {
- elem = list_set_elem(map, i + 1);
+ if (i < map->size) {
+ elem = list_set_elem(map, i);
+ return elem->id == id;
+ }
+
+ return 0;
+}
+
+static bool
+id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
+{
+ const struct set_elem *elem;
+
+ if (i < map->size) {
+ elem = list_set_elem(map, i);
return !!(elem->id == id &&
!(with_timeout(map->timeout) &&
- list_set_expired(map, i + 1)));
+ list_set_expired(map, i)));
}
return 0;
@@ -190,12 +203,26 @@ list_set_del(struct list_set *map, u32 i)
return 0;
}
+static void
+cleanup_entries(struct list_set *map)
+{
+ struct set_telem *e;
+ u32 i;
+
+ for (i = 0; i < map->size; i++) {
+ e = list_set_telem(map, i);
+ if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
+ list_set_del(map, i);
+ }
+}
+
static int
list_set_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags)
{
struct list_set *map = set->data;
bool with_timeout = with_timeout(map->timeout);
+ bool flag_exist = flags & IPSET_FLAG_EXIST;
int before = 0;
u32 timeout = map->timeout;
ip_set_id_t id, refid = IPSET_INVALID_ID;
@@ -248,6 +275,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
}
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
+ if (with_timeout && adt != IPSET_TEST)
+ cleanup_entries(map);
switch (adt) {
case IPSET_TEST:
@@ -259,22 +288,37 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
else if (with_timeout && list_set_expired(map, i))
continue;
else if (before > 0 && elem->id == id)
- ret = next_id_eq(map, i, refid);
+ ret = id_eq_timeout(map, i + 1, refid);
else if (before < 0 && elem->id == refid)
- ret = next_id_eq(map, i, id);
+ ret = id_eq_timeout(map, i + 1, id);
else if (before == 0 && elem->id == id)
ret = 1;
}
break;
case IPSET_ADD:
- for (i = 0; i < map->size && !ret; i++) {
+ for (i = 0; i < map->size; i++) {
elem = list_set_elem(map, i);
- if (elem->id == id &&
- !(with_timeout && list_set_expired(map, i)))
+ if (elem->id != id)
+ continue;
+ if (!(with_timeout && flag_exist)) {
ret = -IPSET_ERR_EXIST;
+ goto finish;
+ } else {
+ struct set_telem *e = list_set_telem(map, i);
+
+ if ((before > 1 &&
+ !id_eq(map, i + 1, refid)) ||
+ (before < 0 &&
+ (i == 0 || !id_eq(map, i - 1, refid)))) {
+ ret = -IPSET_ERR_EXIST;
+ goto finish;
+ }
+ e->timeout = ip_set_timeout_set(timeout);
+ ip_set_put_byindex(id);
+ ret = 0;
+ goto finish;
+ }
}
- if (ret == -IPSET_ERR_EXIST)
- break;
ret = -IPSET_ERR_LIST_FULL;
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
elem = list_set_elem(map, i);
@@ -283,9 +327,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
: list_set_add(map, i, id, timeout);
else if (elem->id != refid)
continue;
- else if (with_timeout && list_set_expired(map, i))
- ret = -IPSET_ERR_REF_EXIST;
- else if (before)
+ else if (before > 0)
ret = list_set_add(map, i, id, timeout);
else if (i + 1 < map->size)
ret = list_set_add(map, i + 1, id, timeout);
@@ -299,16 +341,12 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
ret = before != 0 ? -IPSET_ERR_REF_EXIST
: -IPSET_ERR_EXIST;
break;
- } else if (with_timeout && list_set_expired(map, i))
- continue;
- else if (elem->id == id &&
- (before == 0 ||
- (before > 0 &&
- next_id_eq(map, i, refid))))
+ } else if (elem->id == id &&
+ (before == 0 ||
+ (before > 0 && id_eq(map, i + 1, refid))))
ret = list_set_del(map, i);
- else if (before < 0 &&
- elem->id == refid &&
- next_id_eq(map, i, id))
+ else if (elem->id == refid &&
+ before < 0 && id_eq(map, i + 1, id))
ret = list_set_del(map, i + 1);
}
break;
@@ -454,15 +492,9 @@ list_set_gc(unsigned long ul_set)
{
struct ip_set *set = (struct ip_set *) ul_set;
struct list_set *map = set->data;
- struct set_telem *e;
- u32 i;
write_lock_bh(&set->lock);
- for (i = 0; i < map->size; i++) {
- e = list_set_telem(map, i);
- if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
- list_set_del(map, i);
- }
+ cleanup_entries(map);
write_unlock_bh(&set->lock);
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
diff --git a/tests/bitmap:ip.t b/tests/bitmap:ip.t
index 40c2a98..271bf89 100644
--- a/tests/bitmap:ip.t
+++ b/tests/bitmap:ip.t
@@ -148,6 +148,16 @@
0 ipset list test > .foo
# Full: Check listing
0 diff -I 'Size in memory.*' .foo bitmap:ip.t.list3 && rm .foo
+# Full: flush set
+0 ipset flush test
+# Full: add element with 1s timeout
+0 ipset add test 1.1.1.1 timeout 1
+# Full: readd element with 3s timeout
+0 ipset add test 1.1.1.1 timeout 3 -exist
+# Full: sleep 2s
+0 sleep 2s
+# Full: check readded element
+0 ipset test test 1.1.1.1
# Full: Delete test set
0 ipset destroy test
# eof
diff --git a/tests/hash:ip.t b/tests/hash:ip.t
index a054751..ce8b14b 100644
--- a/tests/hash:ip.t
+++ b/tests/hash:ip.t
@@ -96,6 +96,14 @@
0 diff -I 'Size in memory.*' .foo hash:ip.t.list1 && rm .foo
# Network: Flush test set
0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12
# Network: Delete test set
0 ipset -X test
# eof
diff --git a/tests/macipmap.t b/tests/macipmap.t
index ddc1393..7332f75 100644
--- a/tests/macipmap.t
+++ b/tests/macipmap.t
@@ -130,6 +130,14 @@
0 diff -I 'Size in memory.*' .foo macipmap.t.list2 && rm .foo
# Range: Flush test set
0 ipset -F test
+# Range: add element with 1s timeout
+0 ipset add test 2.0.200.214,00:11:22:33:44:57 timeout 1
+# Range: readd element with 3s timeout
+0 ipset add test 2.0.200.214,00:11:22:33:44:57 timeout 3 -exist
+# Range: sleep 2s
+0 sleep 2s
+# Range: check readded element
+0 ipset test test 2.0.200.214
# Range: Delete test set
0 ipset -X test
# eof
diff --git a/tests/portmap.t b/tests/portmap.t
index 989a83b..084d68c 100644
--- a/tests/portmap.t
+++ b/tests/portmap.t
@@ -80,6 +80,14 @@
# 0 diff -I 'Size in memory.*' .foo portmap.t.list2 && rm .foo
# Full: Flush test set
0 ipset -F test
+# Full: add element with 1s timeout
+0 ipset add test 567 timeout 1
+# Full: readd element with 3s timeout
+0 ipset add test 567 timeout 3 -exist
+# Full: sleep 2s
+0 sleep 2s
+# Full: check readded element
+0 ipset test test 567
# Full: Delete test set
0 ipset -X test
# eof
diff --git a/tests/setlist.t b/tests/setlist.t
index a322cd4..8dcf54a 100644
--- a/tests/setlist.t
+++ b/tests/setlist.t
@@ -52,6 +52,38 @@
0 ipset -F
# Delete all sets
0 ipset -X && rm setlist.t.r
+# Create sets a, b, c to check before/after in all combinations
+0 ipset restore < setlist.t.before
+# Add set a to test set
+0 ipset add test b
+# Add set c after b
+0 ipset add test c after b
+# Add set a before b
+0 ipset add test a before b
+# List test set
+0 ipset list test > .foo
+# Check listing
+0 diff -I 'Size in memory.*' .foo setlist.t.list1 && rm .foo
+# Test a set before b
+0 ipset test test a before b
+# Test c set after b
+0 ipset test test c after b
+# Delete b set before c
+0 ipset del test b before c
+# List test set
+0 ipset list test > .foo
+# Check listing
+0 diff -I 'Size in memory.*' .foo setlist.t.list2 && rm .foo
+# Delete c set after a
+0 ipset del test c after a
+# List test set
+0 ipset list test > .foo
+# Check listing
+0 diff -I 'Size in memory.*' .foo setlist.t.list3 && rm .foo
+# Flush sets
+0 ipset flush
+# Destroy sets
+0 ipset destroy
# Restore list:set with timeout
0 ipset -R < setlist.t.restore
# Add set "before" last one
@@ -84,6 +116,17 @@
0 sleep 10
# Check reference numbers of the sets
0 ref=`ipset list | grep 'References: 1' | wc -l` && test $ref -eq 0
+# Flush test set
+0 ipset flush test
+# Add element with 1s timeout
+0 ipset add test a timeout 1
+# Readd element with 3s timeout
+0 ipset add test a timeout 3 -exist
+# Sleep 2s
+# Check readded element
+0 ipset test test a
+# Flush all sets
+0 ipset flush
# Delete all sets
0 ipset -x
# eof
diff --git a/tests/setlist.t.before b/tests/setlist.t.before
new file mode 100644
index 0000000..59ee644
--- /dev/null
+++ b/tests/setlist.t.before
@@ -0,0 +1,4 @@
+create a hash:ip
+create b hash:ip
+create c hash:ip
+create test list:set
diff --git a/tests/setlist.t.list1 b/tests/setlist.t.list1
new file mode 100644
index 0000000..7bba167
--- /dev/null
+++ b/tests/setlist.t.list1
@@ -0,0 +1,10 @@
+Name: test
+Type: list:set
+Header: size 8
+Size in memory: 120
+References: 0
+Members:
+a
+b
+c
+
diff --git a/tests/setlist.t.list2 b/tests/setlist.t.list2
new file mode 100644
index 0000000..2dc752a
--- /dev/null
+++ b/tests/setlist.t.list2
@@ -0,0 +1,9 @@
+Name: test
+Type: list:set
+Header: size 8
+Size in memory: 120
+References: 0
+Members:
+a
+c
+
diff --git a/tests/setlist.t.list3 b/tests/setlist.t.list3
new file mode 100644
index 0000000..5abe9e4
--- /dev/null
+++ b/tests/setlist.t.list3
@@ -0,0 +1,8 @@
+Name: test
+Type: list:set
+Header: size 8
+Size in memory: 120
+References: 0
+Members:
+a
+