summaryrefslogtreecommitdiffstats
path: root/net/netfilter/ipset/ip_set_list_set.c
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-06-16 18:40:55 +0200
committerPatrick McHardy <kaber@trash.net>2011-06-16 18:40:55 +0200
commit5416219e5ca4504ea80d662fdda7337e52e86ee5 (patch)
treeb98c31ccbcb1d36fadac61e4862655749998af43 /net/netfilter/ipset/ip_set_list_set.c
parent619c15171f6f58681013cdd439632505fd563ba6 (diff)
netfilter: ipset: 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 Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter/ipset/ip_set_list_set.c')
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c92
1 files changed, 62 insertions, 30 deletions
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index e9159e99fc4..a0290ffad35 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/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;