On 11/7/22 03:54, Jozsef Kadlecsik wrote: > On Wed, 28 Sep 2022, Vishwanath Pai wrote: > >> Add a new parameter to complement the existing 'netmask' option. The >> main difference between netmask and bitmask is that bitmask takes any >> arbitrary ip address as input, it does not have to be a valid netmask. >> >> The name of the new parameter is 'bitmask'. This lets us mask out >> arbitrary bits in the ip address, for example: >> ipset create set1 hash:ip bitmask 255.128.255.0 >> ipset create set2 hash:ip,port family inet6 bitmask ffff::ff80 >> >> Signed-off-by: Vishwanath Pai <vpai@xxxxxxxxxx> >> Signed-off-by: Joshua Hunt <johunt@xxxxxxxxxx> >> --- >> >> Notes: >> Changes in v2 based on code review comments: >> * bitmask and netmask options are mutually exclusive now >> * Added tests for the bitmask feature to all three set types >> * IP_SET_HASH_WITH_BITMASK is a separate macro now >> * netmask is now converted and stored as 'bitmask' and bitmask is >> applied to the entries directly for better efficiency >> * fixed comment for revision 6 in hash:ip >> * removed netmask from hash:net,net, it has a cidr option already >> >> include/linux/netfilter.h | 9 +++ >> include/uapi/linux/netfilter/ipset/ip_set.h | 2 + >> net/netfilter/ipset/ip_set_hash_gen.h | 75 +++++++++++++++++---- >> net/netfilter/ipset/ip_set_hash_ip.c | 19 +++--- >> net/netfilter/ipset/ip_set_hash_ipport.c | 24 ++++++- >> net/netfilter/ipset/ip_set_hash_netnet.c | 24 +++++-- >> 6 files changed, 124 insertions(+), 29 deletions(-) >> >> diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h >> index c2c6f332fb90..c7155eaebc84 100644 >> --- a/include/linux/netfilter.h >> +++ b/include/linux/netfilter.h >> @@ -56,6 +56,15 @@ static inline void nf_inet_addr_mask(const union nf_inet_addr *a1, >> #endif >> } >> >> +static inline void nf_inet_addr_mask_inplace(union nf_inet_addr *a1, >> + const union nf_inet_addr *mask) >> +{ >> + a1->all[0] &= mask->all[0]; >> + a1->all[1] &= mask->all[1]; >> + a1->all[2] &= mask->all[2]; >> + a1->all[3] &= mask->all[3]; >> +} >> + > > I see that the natural place for the new inline function is in > include/linux/netfilter.h but the only user is ipset. So probably it'd be > better to move it into include/linux/netfilter/ipset/ip_set.h. I leave it > up to you. > >> int netfilter_init(void); >> >> struct sk_buff; >> diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h >> index 6397d75899bc..1bfa765a2191 100644 >> --- a/include/uapi/linux/netfilter/ipset/ip_set.h >> +++ b/include/uapi/linux/netfilter/ipset/ip_set.h >> @@ -89,6 +89,7 @@ enum { >> IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ >> IPSET_ATTR_MARK, /* 10 */ >> IPSET_ATTR_MARKMASK, /* 11 */ >> + IPSET_ATTR_BITMASK, /* 12 */ >> /* Reserve empty slots */ >> IPSET_ATTR_CADT_MAX = 16, >> /* Create-only specific attributes */ >> @@ -157,6 +158,7 @@ enum ipset_errno { >> IPSET_ERR_COMMENT, >> IPSET_ERR_INVALID_MARKMASK, >> IPSET_ERR_SKBINFO, >> + IPSET_ERR_BITMASK_NETMASK_EXCL, >> >> /* Type specific error codes */ >> IPSET_ERR_TYPE_SPECIFIC = 4352, >> diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h >> index 6e391308431d..1f1b106a2cd8 100644 >> --- a/net/netfilter/ipset/ip_set_hash_gen.h >> +++ b/net/netfilter/ipset/ip_set_hash_gen.h >> @@ -182,6 +182,17 @@ htable_size(u8 hbits) >> (SET_WITH_TIMEOUT(set) && \ >> ip_set_timeout_expired(ext_timeout(d, set))) >> >> +#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK) >> +static const union nf_inet_addr onesmask = { >> + .all[0] = 0xffffffff, >> + .all[1] = 0xffffffff, >> + .all[2] = 0xffffffff, >> + .all[3] = 0xffffffff >> +}; >> + >> +static const union nf_inet_addr zeromask; > > I might be paranoid but I'd like to see an explicit setting to zero, i.e. > > static const union nf_inet_addr zeromask = {}; > >> +#endif >> + >> #endif /* _IP_SET_HASH_GEN_H */ >> >> #ifndef MTYPE >> @@ -306,8 +317,9 @@ struct htype { >> u32 markmask; /* markmask value for mark mask to store */ >> #endif >> u8 bucketsize; /* max elements in an array block */ >> -#ifdef IP_SET_HASH_WITH_NETMASK >> +#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK) >> u8 netmask; /* netmask value for subnets to store */ >> + union nf_inet_addr bitmask; /* stores bitmask */ >> #endif >> struct list_head ad; /* Resize add|del backlist */ >> struct mtype_elem next; /* temporary storage for uadd */ >> @@ -482,8 +494,8 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b) >> /* Resizing changes htable_bits, so we ignore it */ >> return x->maxelem == y->maxelem && >> a->timeout == b->timeout && >> -#ifdef IP_SET_HASH_WITH_NETMASK >> - x->netmask == y->netmask && >> +#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK) >> + nf_inet_addr_cmp(&x->bitmask, &y->bitmask) && >> #endif >> #ifdef IP_SET_HASH_WITH_MARKMASK >> x->markmask == y->markmask && >> @@ -1282,9 +1294,21 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) >> htonl(jhash_size(htable_bits))) || >> nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) >> goto nla_put_failure; >> +#ifdef IP_SET_HASH_WITH_BITMASK >> + /* if netmask is set to anything other than HOST_MASK we know that the user supplied netmask >> + * and not bitmask. These two are mutually exclusive. */ >> + if (h->netmask == HOST_MASK && !nf_inet_addr_cmp(&onesmask, &h->bitmask)) { >> + if (set->family == NFPROTO_IPV4) { >> + if (nla_put_ipaddr4(skb, IPSET_ATTR_BITMASK, h->bitmask.ip)) >> + goto nla_put_failure; >> + } else if (set->family == NFPROTO_IPV6) { >> + if (nla_put_ipaddr6(skb, IPSET_ATTR_BITMASK, &h->bitmask.in6)) >> + goto nla_put_failure; >> + } >> + } >> +#endif >> #ifdef IP_SET_HASH_WITH_NETMASK >> - if (h->netmask != HOST_MASK && >> - nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask)) >> + if (h->netmask != HOST_MASK && nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask)) >> goto nla_put_failure; >> #endif >> #ifdef IP_SET_HASH_WITH_MARKMASK >> @@ -1447,8 +1471,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, >> u32 markmask; >> #endif >> u8 hbits; >> -#ifdef IP_SET_HASH_WITH_NETMASK >> - u8 netmask; >> +#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK) >> + int ret __attribute__((unused)) = 0; >> + u8 netmask = set->family == NFPROTO_IPV4 ? 32 : 128; >> + union nf_inet_addr bitmask = onesmask; >> #endif >> size_t hsize; >> struct htype *h; >> @@ -1486,13 +1512,37 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, >> #endif >> >> #ifdef IP_SET_HASH_WITH_NETMASK >> - netmask = set->family == NFPROTO_IPV4 ? 32 : 128; >> if (tb[IPSET_ATTR_NETMASK]) { >> netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); >> - >> if ((set->family == NFPROTO_IPV4 && netmask > 32) || >> - (set->family == NFPROTO_IPV6 && netmask > 128) || >> - netmask == 0) > > Why is the checking against zero value removed? > > Best regards, > Jozsef > >> + (set->family == NFPROTO_IPV6 && netmask > 128)) >> + return -IPSET_ERR_INVALID_NETMASK; >> + >> + /* we convert netmask to bitmask and store it */ >> + if (set->family == NFPROTO_IPV4) >> + bitmask.ip = ip_set_netmask(netmask); >> + else >> + ip6_netmask(&bitmask, netmask); >> + } >> +#endif >> + >> +#ifdef IP_SET_HASH_WITH_BITMASK >> + if (tb[IPSET_ATTR_BITMASK]) { >> + /* bitmask and netmask do the same thing, allow only one of these options */ >> + if (tb[IPSET_ATTR_NETMASK]) >> + return -IPSET_ERR_BITMASK_NETMASK_EXCL; >> + >> + if (set->family == NFPROTO_IPV4) { >> + ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_BITMASK], &bitmask.ip); >> + if (ret || !bitmask.ip) >> + return -IPSET_ERR_INVALID_NETMASK; >> + } else if (set->family == NFPROTO_IPV6) { >> + ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_BITMASK], &bitmask); >> + if (ret || ipv6_addr_any(&bitmask.in6)) >> + return -IPSET_ERR_INVALID_NETMASK; >> + } >> + >> + if (nf_inet_addr_cmp(&bitmask, &zeromask)) >> return -IPSET_ERR_INVALID_NETMASK; >> } >> #endif >> @@ -1536,7 +1586,8 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, >> for (i = 0; i < ahash_numof_locks(hbits); i++) >> spin_lock_init(&t->hregion[i].lock); >> h->maxelem = maxelem; >> -#ifdef IP_SET_HASH_WITH_NETMASK >> +#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK) >> + h->bitmask = bitmask; >> h->netmask = netmask; >> #endif >> #ifdef IP_SET_HASH_WITH_MARKMASK >> diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c >> index 75d556d71652..e30513cefd90 100644 >> --- a/net/netfilter/ipset/ip_set_hash_ip.c >> +++ b/net/netfilter/ipset/ip_set_hash_ip.c >> @@ -24,7 +24,8 @@ >> /* 2 Comments support */ >> /* 3 Forceadd support */ >> /* 4 skbinfo support */ >> -#define IPSET_TYPE_REV_MAX 5 /* bucketsize, initval support */ >> +/* 5 bucketsize, initval support */ >> +#define IPSET_TYPE_REV_MAX 6 /* bitmask support */ >> >> MODULE_LICENSE("GPL"); >> MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx>"); >> @@ -34,6 +35,7 @@ MODULE_ALIAS("ip_set_hash:ip"); >> /* Type specific function prefix */ >> #define HTYPE hash_ip >> #define IP_SET_HASH_WITH_NETMASK >> +#define IP_SET_HASH_WITH_BITMASK >> >> /* IPv4 variant */ >> >> @@ -86,7 +88,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, >> __be32 ip; >> >> ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); >> - ip &= ip_set_netmask(h->netmask); >> + ip &= h->bitmask.ip; >> if (ip == 0) >> return -EINVAL; >> >> @@ -119,7 +121,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], >> if (ret) >> return ret; >> >> - ip &= ip_set_hostmask(h->netmask); >> + ip &= ntohl(h->bitmask.ip); >> e.ip = htonl(ip); >> if (e.ip == 0) >> return -IPSET_ERR_HASH_ELEM; >> @@ -185,12 +187,6 @@ hash_ip6_data_equal(const struct hash_ip6_elem *ip1, >> return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6); >> } >> >> -static void >> -hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix) >> -{ >> - ip6_netmask(ip, prefix); >> -} >> - >> static bool >> hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e) >> { >> @@ -227,7 +223,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, >> struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); >> >> ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); >> - hash_ip6_netmask(&e.ip, h->netmask); >> + nf_inet_addr_mask_inplace(&e.ip, &h->bitmask); >> if (ipv6_addr_any(&e.ip.in6)) >> return -EINVAL; >> >> @@ -266,7 +262,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], >> if (ret) >> return ret; >> >> - hash_ip6_netmask(&e.ip, h->netmask); >> + nf_inet_addr_mask_inplace(&e.ip, &h->bitmask); >> if (ipv6_addr_any(&e.ip.in6)) >> return -IPSET_ERR_HASH_ELEM; >> >> @@ -293,6 +289,7 @@ static struct ip_set_type hash_ip_type __read_mostly = { >> [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, >> [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, >> [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, >> + [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED }, >> [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, >> }, >> .adt_policy = { >> diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c >> index 7303138e46be..2ffbd0b78a8c 100644 >> --- a/net/netfilter/ipset/ip_set_hash_ipport.c >> +++ b/net/netfilter/ipset/ip_set_hash_ipport.c >> @@ -26,7 +26,8 @@ >> /* 3 Comments support added */ >> /* 4 Forceadd support added */ >> /* 5 skbinfo support added */ >> -#define IPSET_TYPE_REV_MAX 6 /* bucketsize, initval support added */ >> +/* 6 bucketsize, initval support added */ >> +#define IPSET_TYPE_REV_MAX 7 /* bitmask support added */ >> >> MODULE_LICENSE("GPL"); >> MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx>"); >> @@ -35,6 +36,8 @@ MODULE_ALIAS("ip_set_hash:ip,port"); >> >> /* Type specific function prefix */ >> #define HTYPE hash_ipport >> +#define IP_SET_HASH_WITH_NETMASK >> +#define IP_SET_HASH_WITH_BITMASK >> >> /* IPv4 variant */ >> >> @@ -92,12 +95,16 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, >> ipset_adtfn adtfn = set->variant->adt[adt]; >> struct hash_ipport4_elem e = { .ip = 0 }; >> struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); >> + const struct MTYPE *h = set->data; >> >> if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, >> &e.port, &e.proto)) >> return -EINVAL; >> >> ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); >> + e.ip &= h->bitmask.ip; >> + if (e.ip == 0) >> + return -EINVAL; >> return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); >> } >> >> @@ -129,6 +136,10 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], >> if (ret) >> return ret; >> >> + e.ip &= h->bitmask.ip; >> + if (e.ip == 0) >> + return -EINVAL; >> + >> e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); >> >> if (tb[IPSET_ATTR_PROTO]) { >> @@ -253,12 +264,17 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, >> ipset_adtfn adtfn = set->variant->adt[adt]; >> struct hash_ipport6_elem e = { .ip = { .all = { 0 } } }; >> struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); >> + const struct MTYPE *h = set->data; >> >> if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, >> &e.port, &e.proto)) >> return -EINVAL; >> >> ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); >> + nf_inet_addr_mask_inplace(&e.ip, &h->bitmask); >> + if (ipv6_addr_any(&e.ip.in6)) >> + return -EINVAL; >> + >> return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); >> } >> >> @@ -298,6 +314,10 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], >> if (ret) >> return ret; >> >> + nf_inet_addr_mask_inplace(&e.ip, &h->bitmask); >> + if (ipv6_addr_any(&e.ip.in6)) >> + return -EINVAL; >> + >> e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); >> >> if (tb[IPSET_ATTR_PROTO]) { >> @@ -356,6 +376,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = { >> [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, >> [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, >> [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, >> + [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, >> + [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED }, >> }, >> .adt_policy = { >> [IPSET_ATTR_IP] = { .type = NLA_NESTED }, >> diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c >> index 3d09eefe998a..c514ac19486d 100644 >> --- a/net/netfilter/ipset/ip_set_hash_netnet.c >> +++ b/net/netfilter/ipset/ip_set_hash_netnet.c >> @@ -23,7 +23,8 @@ >> #define IPSET_TYPE_REV_MIN 0 >> /* 1 Forceadd support added */ >> /* 2 skbinfo support added */ >> -#define IPSET_TYPE_REV_MAX 3 /* bucketsize, initval support added */ >> +/* 3 bucketsize, initval support added */ >> +#define IPSET_TYPE_REV_MAX 4 /* bitmask support added */ >> >> MODULE_LICENSE("GPL"); >> MODULE_AUTHOR("Oliver Smith <oliver@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>"); >> @@ -33,6 +34,7 @@ MODULE_ALIAS("ip_set_hash:net,net"); >> /* Type specific function prefix */ >> #define HTYPE hash_netnet >> #define IP_SET_HASH_WITH_NETS >> +#define IP_SET_HASH_WITH_BITMASK >> #define IPSET_NET_COUNT 2 >> >> /* IPv4 variants */ >> @@ -153,8 +155,8 @@ hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb, >> >> ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]); >> ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]); >> - e.ip[0] &= ip_set_netmask(e.cidr[0]); >> - e.ip[1] &= ip_set_netmask(e.cidr[1]); >> + e.ip[0] &= (ip_set_netmask(e.cidr[0]) & h->bitmask.ip); >> + e.ip[1] &= (ip_set_netmask(e.cidr[1]) & h->bitmask.ip); >> >> return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); >> } >> @@ -213,8 +215,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], >> >> if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] || >> tb[IPSET_ATTR_IP2_TO])) { >> - e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); >> - e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); >> + e.ip[0] = htonl(ip & ntohl(h->bitmask.ip) & ip_set_hostmask(e.cidr[0])); >> + e.ip[1] = htonl(ip2_from & ntohl(h->bitmask.ip) & ip_set_hostmask(e.cidr[1])); >> ret = adtfn(set, &e, &ext, &ext, flags); >> return ip_set_enomatch(ret, flags, adt, set) ? -ret : >> ip_set_eexist(ret, flags) ? 0 : ret; >> @@ -404,6 +406,11 @@ hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb, >> ip6_netmask(&e.ip[0], e.cidr[0]); >> ip6_netmask(&e.ip[1], e.cidr[1]); >> >> + nf_inet_addr_mask_inplace(&e.ip[0], &h->bitmask); >> + nf_inet_addr_mask_inplace(&e.ip[1], &h->bitmask); >> + if (e.cidr[0] == HOST_MASK && ipv6_addr_any(&e.ip[0].in6)) >> + return -EINVAL; >> + >> return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); >> } >> >> @@ -414,6 +421,7 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], >> ipset_adtfn adtfn = set->variant->adt[adt]; >> struct hash_netnet6_elem e = { }; >> struct ip_set_ext ext = IP_SET_INIT_UEXT(set); >> + const struct hash_netnet6 *h = set->data; >> int ret; >> >> if (tb[IPSET_ATTR_LINENO]) >> @@ -453,6 +461,11 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], >> ip6_netmask(&e.ip[0], e.cidr[0]); >> ip6_netmask(&e.ip[1], e.cidr[1]); >> >> + nf_inet_addr_mask_inplace(&e.ip[0], &h->bitmask); >> + nf_inet_addr_mask_inplace(&e.ip[1], &h->bitmask); >> + if (e.cidr[0] == HOST_MASK && ipv6_addr_any(&e.ip[0].in6)) >> + return -IPSET_ERR_HASH_ELEM; >> + >> if (tb[IPSET_ATTR_CADT_FLAGS]) { >> u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); >> >> @@ -484,6 +497,7 @@ static struct ip_set_type hash_netnet_type __read_mostly = { >> [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, >> [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, >> [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, >> + [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED }, >> }, >> .adt_policy = { >> [IPSET_ATTR_IP] = { .type = NLA_NESTED }, >> -- >> 2.25.1 >> >> > > - > E-mail : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxx > PGP key : https://urldefense.com/v3/__https://wigner.hu/*kadlec/pgp_public_key.txt__;fg!!GjvTz_vk!Xn_l6E1kmVXKtEbuYab4N5VJx_U3sgMqLvuIZRo0CmSCwHfx92iRGEVzSAfVpHZfJCxHOcNwrG9miA$ > Address : Wigner Research Centre for Physics > H-1525 Budapest 114, POB. 49, Hungary Hi Jozsef, Thanks for taking a look at the patches. > Why is the checking against zero value removed? Ah, yes this shouldn't have been removed. I removed it because I set netmask to 32/64 above, but here we are fetching the value from userspace so we should check for zero. I will fix it. I will address the other comments and send a v3 in a couple of days. Thanks, Vishwanath