diff options
Diffstat (limited to 'kernel/include')
-rw-r--r-- | kernel/include/linux/netfilter/ipset/ip_set.h | 2 | ||||
-rw-r--r-- | kernel/include/linux/netfilter/ipset/ip_set_ahash.h | 22 |
2 files changed, 20 insertions, 4 deletions
diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h index e677c4d..710ba00 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set.h +++ b/kernel/include/linux/netfilter/ipset/ip_set.h @@ -244,7 +244,7 @@ struct ip_set_type_variant { * zero for no match/success to add/delete * positive for matching element */ int (*uadt)(struct ip_set *set, struct nlattr *tb[], - enum ipset_adt adt, u32 *lineno, u32 flags); + enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); /* Low level add/del/test functions */ ipset_adtfn adt[IPSET_ADT_MAX]; diff --git a/kernel/include/linux/netfilter/ipset/ip_set_ahash.h b/kernel/include/linux/netfilter/ipset/ip_set_ahash.h index 690fa69..6a4969d 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/kernel/include/linux/netfilter/ipset/ip_set_ahash.h @@ -5,6 +5,11 @@ #include <linux/jhash.h> #include <linux/netfilter/ipset/ip_set_timeout.h> +#define CONCAT(a, b, c) a##b##c +#define TOKEN(a, b, c) CONCAT(a, b, c) + +#define type_pf_next TOKEN(TYPE, PF, _elem) + /* Hashing which uses arrays to resolve clashing. The hash table is resized * (doubled) when searching becomes too long. * Internally jhash is used with the assumption that the size of the @@ -54,6 +59,7 @@ struct ip_set_hash { u32 initval; /* random jhash init value */ u32 timeout; /* timeout value, if enabled */ struct timer_list gc; /* garbage collection when timeout enabled */ + struct type_pf_next next; /* temporary storage for uadd */ #ifdef IP_SET_HASH_WITH_NETMASK u8 netmask; /* netmask value for subnets to store */ #endif @@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set) #define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) #define type_pf_data_list TOKEN(TYPE, PF, _data_list) #define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) +#define type_pf_data_next TOKEN(TYPE, PF, _data_next) #define type_pf_elem TOKEN(TYPE, PF, _elem) #define type_pf_telem TOKEN(TYPE, PF, _telem) @@ -346,6 +353,9 @@ retry: return 0; } +static inline void +type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d); + /* Add an element to a hash and update the internal counters when succeeded, * otherwise report the proper error code. */ static int @@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) } ret = type_pf_elem_add(n, value); - if (ret != 0) + if (ret != 0) { + if (ret == -EAGAIN) + type_pf_data_next(h, d); goto out; + } #ifdef IP_SET_HASH_WITH_NETS add_cidr(h, d->cidr, HOST_MASK); @@ -589,7 +602,7 @@ type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, enum ipset_adt adt, const struct ip_set_adt_opt *opt); static int type_pf_uadt(struct ip_set *set, struct nlattr *tb[], - enum ipset_adt adt, u32 *lineno, u32 flags); + enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); static const struct ip_set_type_variant type_pf_variant = { .kadt = type_pf_kadt, @@ -821,8 +834,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) goto out; } ret = type_pf_elem_tadd(n, d, timeout); - if (ret != 0) + if (ret != 0) { + if (ret == -EEXIST) + type_pf_data_next(h, d); goto out; + } #ifdef IP_SET_HASH_WITH_NETS add_cidr(h, d->cidr, HOST_MASK); |