Commit 5416219e authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Patrick McHardy

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: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent 619c1517
......@@ -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 {
......
......@@ -349,7 +349,7 @@ type_pf_resize(struct ip_set *set, bool retried)
/* 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 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout)
* 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 @@ type_pf_tresize(struct ip_set *set, bool retried)
}
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 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
}
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;
......
......@@ -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 @@ bitmap_ip_list(const struct ip_set *set,
/* 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;
......
......@@ -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 @@ bitmap_ipmac_list(const struct ip_set *set,
/* 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;
......@@ -359,7 +360,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
......@@ -399,7 +400,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;
}
......
......@@ -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 @@ bitmap_port_list(const struct ip_set *set,
/* 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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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 &&
} else if (elem->id == id &&
(before == 0 ||
(before > 0 &&
next_id_eq(map, i, refid))))
(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;
......
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