Commit 72205fc68bd13109576aa6c4c12c740962d28a6c

Authored by Jozsef Kadlecsik
Committed by Patrick McHardy
1 parent a7b4f989a6

netfilter: ipset: bitmap:ip set type support

The module implements the bitmap:ip set type in two flavours, without
and with timeout support. In this kind of set one can store IPv4
addresses (or network addresses) from a given range.

In order not to waste memory, the timeout version does not rely on
the kernel timer for every element to be timed out but on garbage
collection. All set types use this mechanism.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>

Showing 5 changed files with 758 additions and 0 deletions Side-by-side Diff

include/linux/netfilter/ipset/ip_set_bitmap.h
  1 +#ifndef __IP_SET_BITMAP_H
  2 +#define __IP_SET_BITMAP_H
  3 +
  4 +/* Bitmap type specific error codes */
  5 +enum {
  6 + /* The element is out of the range of the set */
  7 + IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
  8 + /* The range exceeds the size limit of the set type */
  9 + IPSET_ERR_BITMAP_RANGE_SIZE,
  10 +};
  11 +
  12 +#ifdef __KERNEL__
  13 +#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF
  14 +
  15 +/* Common functions */
  16 +
  17 +static inline u32
  18 +range_to_mask(u32 from, u32 to, u8 *bits)
  19 +{
  20 + u32 mask = 0xFFFFFFFE;
  21 +
  22 + *bits = 32;
  23 + while (--(*bits) > 0 && mask && (to & mask) != from)
  24 + mask <<= 1;
  25 +
  26 + return mask;
  27 +}
  28 +
  29 +#endif /* __KERNEL__ */
  30 +
  31 +#endif /* __IP_SET_BITMAP_H */
include/linux/netfilter/ipset/ip_set_timeout.h
  1 +#ifndef _IP_SET_TIMEOUT_H
  2 +#define _IP_SET_TIMEOUT_H
  3 +
  4 +/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License version 2 as
  8 + * published by the Free Software Foundation.
  9 + */
  10 +
  11 +#ifdef __KERNEL__
  12 +
  13 +/* How often should the gc be run by default */
  14 +#define IPSET_GC_TIME (3 * 60)
  15 +
  16 +/* Timeout period depending on the timeout value of the given set */
  17 +#define IPSET_GC_PERIOD(timeout) \
  18 + ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
  19 +
  20 +/* Set is defined without timeout support: timeout value may be 0 */
  21 +#define IPSET_NO_TIMEOUT UINT_MAX
  22 +
  23 +#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
  24 +
  25 +static inline unsigned int
  26 +ip_set_timeout_uget(struct nlattr *tb)
  27 +{
  28 + unsigned int timeout = ip_set_get_h32(tb);
  29 +
  30 + /* Userspace supplied TIMEOUT parameter: adjust crazy size */
  31 + return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
  32 +}
  33 +
  34 +#ifdef IP_SET_BITMAP_TIMEOUT
  35 +
  36 +/* Bitmap specific timeout constants and macros for the entries */
  37 +
  38 +/* Bitmap entry is unset */
  39 +#define IPSET_ELEM_UNSET 0
  40 +/* Bitmap entry is set with no timeout value */
  41 +#define IPSET_ELEM_PERMANENT (UINT_MAX/2)
  42 +
  43 +static inline bool
  44 +ip_set_timeout_test(unsigned long timeout)
  45 +{
  46 + return timeout != IPSET_ELEM_UNSET &&
  47 + (timeout == IPSET_ELEM_PERMANENT ||
  48 + time_after(timeout, jiffies));
  49 +}
  50 +
  51 +static inline bool
  52 +ip_set_timeout_expired(unsigned long timeout)
  53 +{
  54 + return timeout != IPSET_ELEM_UNSET &&
  55 + timeout != IPSET_ELEM_PERMANENT &&
  56 + time_before(timeout, jiffies);
  57 +}
  58 +
  59 +static inline unsigned long
  60 +ip_set_timeout_set(u32 timeout)
  61 +{
  62 + unsigned long t;
  63 +
  64 + if (!timeout)
  65 + return IPSET_ELEM_PERMANENT;
  66 +
  67 + t = timeout * HZ + jiffies;
  68 + if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
  69 + /* Bingo! */
  70 + t++;
  71 +
  72 + return t;
  73 +}
  74 +
  75 +static inline u32
  76 +ip_set_timeout_get(unsigned long timeout)
  77 +{
  78 + return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
  79 +}
  80 +
  81 +#else
  82 +
  83 +/* Hash specific timeout constants and macros for the entries */
  84 +
  85 +/* Hash entry is set with no timeout value */
  86 +#define IPSET_ELEM_PERMANENT 0
  87 +
  88 +static inline bool
  89 +ip_set_timeout_test(unsigned long timeout)
  90 +{
  91 + return timeout == IPSET_ELEM_PERMANENT ||
  92 + time_after(timeout, jiffies);
  93 +}
  94 +
  95 +static inline bool
  96 +ip_set_timeout_expired(unsigned long timeout)
  97 +{
  98 + return timeout != IPSET_ELEM_PERMANENT &&
  99 + time_before(timeout, jiffies);
  100 +}
  101 +
  102 +static inline unsigned long
  103 +ip_set_timeout_set(u32 timeout)
  104 +{
  105 + unsigned long t;
  106 +
  107 + if (!timeout)
  108 + return IPSET_ELEM_PERMANENT;
  109 +
  110 + t = timeout * HZ + jiffies;
  111 + if (t == IPSET_ELEM_PERMANENT)
  112 + /* Bingo! :-) */
  113 + t++;
  114 +
  115 + return t;
  116 +}
  117 +
  118 +static inline u32
  119 +ip_set_timeout_get(unsigned long timeout)
  120 +{
  121 + return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
  122 +}
  123 +#endif /* ! IP_SET_BITMAP_TIMEOUT */
  124 +
  125 +#endif /* __KERNEL__ */
  126 +
  127 +#endif /* _IP_SET_TIMEOUT_H */
net/netfilter/ipset/Kconfig
... ... @@ -23,5 +23,14 @@
23 23 The value can be overriden by the 'max_sets' module
24 24 parameter of the 'ip_set' module.
25 25  
  26 +config IP_SET_BITMAP_IP
  27 + tristate "bitmap:ip set support"
  28 + depends on IP_SET
  29 + help
  30 + This option adds the bitmap:ip set type support, by which one
  31 + can store IPv4 addresses (or network addresse) from a range.
  32 +
  33 + To compile it as a module, choose M here. If unsure, say N.
  34 +
26 35 endif # IP_SET
net/netfilter/ipset/Makefile
... ... @@ -6,4 +6,7 @@
6 6  
7 7 # ipset core
8 8 obj-$(CONFIG_IP_SET) += ip_set.o
  9 +
  10 +# bitmap types
  11 +obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o
net/netfilter/ipset/ip_set_bitmap_ip.c
  1 +/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  2 + * Patrick Schaaf <bof@bof.de>
  3 + * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  4 + *
  5 + * This program is free software; you can redistribute it and/or modify
  6 + * it under the terms of the GNU General Public License version 2 as
  7 + * published by the Free Software Foundation.
  8 + */
  9 +
  10 +/* Kernel module implementing an IP set type: the bitmap:ip type */
  11 +
  12 +#include <linux/module.h>
  13 +#include <linux/ip.h>
  14 +#include <linux/skbuff.h>
  15 +#include <linux/errno.h>
  16 +#include <linux/uaccess.h>
  17 +#include <linux/bitops.h>
  18 +#include <linux/spinlock.h>
  19 +#include <linux/netlink.h>
  20 +#include <linux/jiffies.h>
  21 +#include <linux/timer.h>
  22 +#include <net/netlink.h>
  23 +#include <net/tcp.h>
  24 +
  25 +#include <linux/netfilter/ipset/pfxlen.h>
  26 +#include <linux/netfilter/ipset/ip_set.h>
  27 +#include <linux/netfilter/ipset/ip_set_bitmap.h>
  28 +#define IP_SET_BITMAP_TIMEOUT
  29 +#include <linux/netfilter/ipset/ip_set_timeout.h>
  30 +
  31 +MODULE_LICENSE("GPL");
  32 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  33 +MODULE_DESCRIPTION("bitmap:ip type of IP sets");
  34 +MODULE_ALIAS("ip_set_bitmap:ip");
  35 +
  36 +/* Type structure */
  37 +struct bitmap_ip {
  38 + void *members; /* the set members */
  39 + u32 first_ip; /* host byte order, included in range */
  40 + u32 last_ip; /* host byte order, included in range */
  41 + u32 elements; /* number of max elements in the set */
  42 + u32 hosts; /* number of hosts in a subnet */
  43 + size_t memsize; /* members size */
  44 + u8 netmask; /* subnet netmask */
  45 + u32 timeout; /* timeout parameter */
  46 + struct timer_list gc; /* garbage collection */
  47 +};
  48 +
  49 +/* Base variant */
  50 +
  51 +static inline u32
  52 +ip_to_id(const struct bitmap_ip *m, u32 ip)
  53 +{
  54 + return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
  55 +}
  56 +
  57 +static int
  58 +bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
  59 +{
  60 + const struct bitmap_ip *map = set->data;
  61 + u16 id = *(u16 *)value;
  62 +
  63 + return !!test_bit(id, map->members);
  64 +}
  65 +
  66 +static int
  67 +bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
  68 +{
  69 + struct bitmap_ip *map = set->data;
  70 + u16 id = *(u16 *)value;
  71 +
  72 + if (test_and_set_bit(id, map->members))
  73 + return -IPSET_ERR_EXIST;
  74 +
  75 + return 0;
  76 +}
  77 +
  78 +static int
  79 +bitmap_ip_del(struct ip_set *set, void *value, u32 timeout)
  80 +{
  81 + struct bitmap_ip *map = set->data;
  82 + u16 id = *(u16 *)value;
  83 +
  84 + if (!test_and_clear_bit(id, map->members))
  85 + return -IPSET_ERR_EXIST;
  86 +
  87 + return 0;
  88 +}
  89 +
  90 +static int
  91 +bitmap_ip_list(const struct ip_set *set,
  92 + struct sk_buff *skb, struct netlink_callback *cb)
  93 +{
  94 + const struct bitmap_ip *map = set->data;
  95 + struct nlattr *atd, *nested;
  96 + u32 id, first = cb->args[2];
  97 +
  98 + atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
  99 + if (!atd)
  100 + return -EMSGSIZE;
  101 + for (; cb->args[2] < map->elements; cb->args[2]++) {
  102 + id = cb->args[2];
  103 + if (!test_bit(id, map->members))
  104 + continue;
  105 + nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
  106 + if (!nested) {
  107 + if (id == first) {
  108 + nla_nest_cancel(skb, atd);
  109 + return -EMSGSIZE;
  110 + } else
  111 + goto nla_put_failure;
  112 + }
  113 + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
  114 + htonl(map->first_ip + id * map->hosts));
  115 + ipset_nest_end(skb, nested);
  116 + }
  117 + ipset_nest_end(skb, atd);
  118 + /* Set listing finished */
  119 + cb->args[2] = 0;
  120 + return 0;
  121 +
  122 +nla_put_failure:
  123 + nla_nest_cancel(skb, nested);
  124 + ipset_nest_end(skb, atd);
  125 + if (unlikely(id == first)) {
  126 + cb->args[2] = 0;
  127 + return -EMSGSIZE;
  128 + }
  129 + return 0;
  130 +}
  131 +
  132 +/* Timeout variant */
  133 +
  134 +static int
  135 +bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
  136 +{
  137 + const struct bitmap_ip *map = set->data;
  138 + const unsigned long *members = map->members;
  139 + u16 id = *(u16 *)value;
  140 +
  141 + return ip_set_timeout_test(members[id]);
  142 +}
  143 +
  144 +static int
  145 +bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
  146 +{
  147 + struct bitmap_ip *map = set->data;
  148 + unsigned long *members = map->members;
  149 + u16 id = *(u16 *)value;
  150 +
  151 + if (ip_set_timeout_test(members[id]))
  152 + return -IPSET_ERR_EXIST;
  153 +
  154 + members[id] = ip_set_timeout_set(timeout);
  155 +
  156 + return 0;
  157 +}
  158 +
  159 +static int
  160 +bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout)
  161 +{
  162 + struct bitmap_ip *map = set->data;
  163 + unsigned long *members = map->members;
  164 + u16 id = *(u16 *)value;
  165 + int ret = -IPSET_ERR_EXIST;
  166 +
  167 + if (ip_set_timeout_test(members[id]))
  168 + ret = 0;
  169 +
  170 + members[id] = IPSET_ELEM_UNSET;
  171 + return ret;
  172 +}
  173 +
  174 +static int
  175 +bitmap_ip_tlist(const struct ip_set *set,
  176 + struct sk_buff *skb, struct netlink_callback *cb)
  177 +{
  178 + const struct bitmap_ip *map = set->data;
  179 + struct nlattr *adt, *nested;
  180 + u32 id, first = cb->args[2];
  181 + const unsigned long *members = map->members;
  182 +
  183 + adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
  184 + if (!adt)
  185 + return -EMSGSIZE;
  186 + for (; cb->args[2] < map->elements; cb->args[2]++) {
  187 + id = cb->args[2];
  188 + if (!ip_set_timeout_test(members[id]))
  189 + continue;
  190 + nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
  191 + if (!nested) {
  192 + if (id == first) {
  193 + nla_nest_cancel(skb, adt);
  194 + return -EMSGSIZE;
  195 + } else
  196 + goto nla_put_failure;
  197 + }
  198 + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
  199 + htonl(map->first_ip + id * map->hosts));
  200 + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
  201 + htonl(ip_set_timeout_get(members[id])));
  202 + ipset_nest_end(skb, nested);
  203 + }
  204 + ipset_nest_end(skb, adt);
  205 +
  206 + /* Set listing finished */
  207 + cb->args[2] = 0;
  208 +
  209 + return 0;
  210 +
  211 +nla_put_failure:
  212 + nla_nest_cancel(skb, nested);
  213 + ipset_nest_end(skb, adt);
  214 + if (unlikely(id == first)) {
  215 + cb->args[2] = 0;
  216 + return -EMSGSIZE;
  217 + }
  218 + return 0;
  219 +}
  220 +
  221 +static int
  222 +bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
  223 + enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
  224 +{
  225 + struct bitmap_ip *map = set->data;
  226 + ipset_adtfn adtfn = set->variant->adt[adt];
  227 + u32 ip;
  228 +
  229 + ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
  230 + if (ip < map->first_ip || ip > map->last_ip)
  231 + return -IPSET_ERR_BITMAP_RANGE;
  232 +
  233 + ip = ip_to_id(map, ip);
  234 +
  235 + return adtfn(set, &ip, map->timeout);
  236 +}
  237 +
  238 +static int
  239 +bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
  240 + enum ipset_adt adt, u32 *lineno, u32 flags)
  241 +{
  242 + struct bitmap_ip *map = set->data;
  243 + ipset_adtfn adtfn = set->variant->adt[adt];
  244 + u32 timeout = map->timeout;
  245 + u32 ip, ip_to, id;
  246 + int ret = 0;
  247 +
  248 + if (unlikely(!tb[IPSET_ATTR_IP] ||
  249 + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
  250 + return -IPSET_ERR_PROTOCOL;
  251 +
  252 + if (tb[IPSET_ATTR_LINENO])
  253 + *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
  254 +
  255 + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
  256 + if (ret)
  257 + return ret;
  258 +
  259 + if (ip < map->first_ip || ip > map->last_ip)
  260 + return -IPSET_ERR_BITMAP_RANGE;
  261 +
  262 + if (tb[IPSET_ATTR_TIMEOUT]) {
  263 + if (!with_timeout(map->timeout))
  264 + return -IPSET_ERR_TIMEOUT;
  265 + timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
  266 + }
  267 +
  268 + if (adt == IPSET_TEST) {
  269 + id = ip_to_id(map, ip);
  270 + return adtfn(set, &id, timeout);
  271 + }
  272 +
  273 + if (tb[IPSET_ATTR_IP_TO]) {
  274 + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
  275 + if (ret)
  276 + return ret;
  277 + if (ip > ip_to) {
  278 + swap(ip, ip_to);
  279 + if (ip < map->first_ip)
  280 + return -IPSET_ERR_BITMAP_RANGE;
  281 + }
  282 + } else if (tb[IPSET_ATTR_CIDR]) {
  283 + u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
  284 +
  285 + if (cidr > 32)
  286 + return -IPSET_ERR_INVALID_CIDR;
  287 + ip &= ip_set_hostmask(cidr);
  288 + ip_to = ip | ~ip_set_hostmask(cidr);
  289 + } else
  290 + ip_to = ip;
  291 +
  292 + if (ip_to > map->last_ip)
  293 + return -IPSET_ERR_BITMAP_RANGE;
  294 +
  295 + for (; !before(ip_to, ip); ip += map->hosts) {
  296 + id = ip_to_id(map, ip);
  297 + ret = adtfn(set, &id, timeout);;
  298 +
  299 + if (ret && !ip_set_eexist(ret, flags))
  300 + return ret;
  301 + else
  302 + ret = 0;
  303 + }
  304 + return ret;
  305 +}
  306 +
  307 +static void
  308 +bitmap_ip_destroy(struct ip_set *set)
  309 +{
  310 + struct bitmap_ip *map = set->data;
  311 +
  312 + if (with_timeout(map->timeout))
  313 + del_timer_sync(&map->gc);
  314 +
  315 + ip_set_free(map->members);
  316 + kfree(map);
  317 +
  318 + set->data = NULL;
  319 +}
  320 +
  321 +static void
  322 +bitmap_ip_flush(struct ip_set *set)
  323 +{
  324 + struct bitmap_ip *map = set->data;
  325 +
  326 + memset(map->members, 0, map->memsize);
  327 +}
  328 +
  329 +static int
  330 +bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
  331 +{
  332 + const struct bitmap_ip *map = set->data;
  333 + struct nlattr *nested;
  334 +
  335 + nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
  336 + if (!nested)
  337 + goto nla_put_failure;
  338 + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
  339 + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
  340 + if (map->netmask != 32)
  341 + NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
  342 + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
  343 + htonl(atomic_read(&set->ref) - 1));
  344 + NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
  345 + htonl(sizeof(*map) + map->memsize));
  346 + if (with_timeout(map->timeout))
  347 + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
  348 + ipset_nest_end(skb, nested);
  349 +
  350 + return 0;
  351 +nla_put_failure:
  352 + return -EMSGSIZE;
  353 +}
  354 +
  355 +static bool
  356 +bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
  357 +{
  358 + const struct bitmap_ip *x = a->data;
  359 + const struct bitmap_ip *y = b->data;
  360 +
  361 + return x->first_ip == y->first_ip &&
  362 + x->last_ip == y->last_ip &&
  363 + x->netmask == y->netmask &&
  364 + x->timeout == y->timeout;
  365 +}
  366 +
  367 +static const struct ip_set_type_variant bitmap_ip = {
  368 + .kadt = bitmap_ip_kadt,
  369 + .uadt = bitmap_ip_uadt,
  370 + .adt = {
  371 + [IPSET_ADD] = bitmap_ip_add,
  372 + [IPSET_DEL] = bitmap_ip_del,
  373 + [IPSET_TEST] = bitmap_ip_test,
  374 + },
  375 + .destroy = bitmap_ip_destroy,
  376 + .flush = bitmap_ip_flush,
  377 + .head = bitmap_ip_head,
  378 + .list = bitmap_ip_list,
  379 + .same_set = bitmap_ip_same_set,
  380 +};
  381 +
  382 +static const struct ip_set_type_variant bitmap_tip = {
  383 + .kadt = bitmap_ip_kadt,
  384 + .uadt = bitmap_ip_uadt,
  385 + .adt = {
  386 + [IPSET_ADD] = bitmap_ip_tadd,
  387 + [IPSET_DEL] = bitmap_ip_tdel,
  388 + [IPSET_TEST] = bitmap_ip_ttest,
  389 + },
  390 + .destroy = bitmap_ip_destroy,
  391 + .flush = bitmap_ip_flush,
  392 + .head = bitmap_ip_head,
  393 + .list = bitmap_ip_tlist,
  394 + .same_set = bitmap_ip_same_set,
  395 +};
  396 +
  397 +static void
  398 +bitmap_ip_gc(unsigned long ul_set)
  399 +{
  400 + struct ip_set *set = (struct ip_set *) ul_set;
  401 + struct bitmap_ip *map = set->data;
  402 + unsigned long *table = map->members;
  403 + u32 id;
  404 +
  405 + /* We run parallel with other readers (test element)
  406 + * but adding/deleting new entries is locked out */
  407 + read_lock_bh(&set->lock);
  408 + for (id = 0; id < map->elements; id++)
  409 + if (ip_set_timeout_expired(table[id]))
  410 + table[id] = IPSET_ELEM_UNSET;
  411 + read_unlock_bh(&set->lock);
  412 +
  413 + map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
  414 + add_timer(&map->gc);
  415 +}
  416 +
  417 +static void
  418 +bitmap_ip_gc_init(struct ip_set *set)
  419 +{
  420 + struct bitmap_ip *map = set->data;
  421 +
  422 + init_timer(&map->gc);
  423 + map->gc.data = (unsigned long) set;
  424 + map->gc.function = bitmap_ip_gc;
  425 + map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
  426 + add_timer(&map->gc);
  427 +}
  428 +
  429 +/* Create bitmap:ip type of sets */
  430 +
  431 +static bool
  432 +init_map_ip(struct ip_set *set, struct bitmap_ip *map,
  433 + u32 first_ip, u32 last_ip,
  434 + u32 elements, u32 hosts, u8 netmask)
  435 +{
  436 + map->members = ip_set_alloc(map->memsize);
  437 + if (!map->members)
  438 + return false;
  439 + map->first_ip = first_ip;
  440 + map->last_ip = last_ip;
  441 + map->elements = elements;
  442 + map->hosts = hosts;
  443 + map->netmask = netmask;
  444 + map->timeout = IPSET_NO_TIMEOUT;
  445 +
  446 + set->data = map;
  447 + set->family = AF_INET;
  448 +
  449 + return true;
  450 +}
  451 +
  452 +static int
  453 +bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
  454 +{
  455 + struct bitmap_ip *map;
  456 + u32 first_ip, last_ip, hosts, elements;
  457 + u8 netmask = 32;
  458 + int ret;
  459 +
  460 + if (unlikely(!tb[IPSET_ATTR_IP] ||
  461 + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
  462 + return -IPSET_ERR_PROTOCOL;
  463 +
  464 + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
  465 + if (ret)
  466 + return ret;
  467 +
  468 + if (tb[IPSET_ATTR_IP_TO]) {
  469 + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
  470 + if (ret)
  471 + return ret;
  472 + if (first_ip > last_ip) {
  473 + u32 tmp = first_ip;
  474 +
  475 + first_ip = last_ip;
  476 + last_ip = tmp;
  477 + }
  478 + } else if (tb[IPSET_ATTR_CIDR]) {
  479 + u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
  480 +
  481 + if (cidr >= 32)
  482 + return -IPSET_ERR_INVALID_CIDR;
  483 + last_ip = first_ip | ~ip_set_hostmask(cidr);
  484 + } else
  485 + return -IPSET_ERR_PROTOCOL;
  486 +
  487 + if (tb[IPSET_ATTR_NETMASK]) {
  488 + netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
  489 +
  490 + if (netmask > 32)
  491 + return -IPSET_ERR_INVALID_NETMASK;
  492 +
  493 + first_ip &= ip_set_hostmask(netmask);
  494 + last_ip |= ~ip_set_hostmask(netmask);
  495 + }
  496 +
  497 + if (netmask == 32) {
  498 + hosts = 1;
  499 + elements = last_ip - first_ip + 1;
  500 + } else {
  501 + u8 mask_bits;
  502 + u32 mask;
  503 +
  504 + mask = range_to_mask(first_ip, last_ip, &mask_bits);
  505 +
  506 + if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) ||
  507 + netmask <= mask_bits)
  508 + return -IPSET_ERR_BITMAP_RANGE;
  509 +
  510 + pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
  511 + hosts = 2 << (32 - netmask - 1);
  512 + elements = 2 << (netmask - mask_bits - 1);
  513 + }
  514 + if (elements > IPSET_BITMAP_MAX_RANGE + 1)
  515 + return -IPSET_ERR_BITMAP_RANGE_SIZE;
  516 +
  517 + pr_debug("hosts %u, elements %u\n", hosts, elements);
  518 +
  519 + map = kzalloc(sizeof(*map), GFP_KERNEL);
  520 + if (!map)
  521 + return -ENOMEM;
  522 +
  523 + if (tb[IPSET_ATTR_TIMEOUT]) {
  524 + map->memsize = elements * sizeof(unsigned long);
  525 +
  526 + if (!init_map_ip(set, map, first_ip, last_ip,
  527 + elements, hosts, netmask)) {
  528 + kfree(map);
  529 + return -ENOMEM;
  530 + }
  531 +
  532 + map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
  533 + set->variant = &bitmap_tip;
  534 +
  535 + bitmap_ip_gc_init(set);
  536 + } else {
  537 + map->memsize = bitmap_bytes(0, elements - 1);
  538 +
  539 + if (!init_map_ip(set, map, first_ip, last_ip,
  540 + elements, hosts, netmask)) {
  541 + kfree(map);
  542 + return -ENOMEM;
  543 + }
  544 +
  545 + set->variant = &bitmap_ip;
  546 + }
  547 + return 0;
  548 +}
  549 +
  550 +static struct ip_set_type bitmap_ip_type __read_mostly = {
  551 + .name = "bitmap:ip",
  552 + .protocol = IPSET_PROTOCOL,
  553 + .features = IPSET_TYPE_IP,
  554 + .dimension = IPSET_DIM_ONE,
  555 + .family = AF_INET,
  556 + .revision = 0,
  557 + .create = bitmap_ip_create,
  558 + .create_policy = {
  559 + [IPSET_ATTR_IP] = { .type = NLA_NESTED },
  560 + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
  561 + [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
  562 + [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
  563 + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  564 + },
  565 + .adt_policy = {
  566 + [IPSET_ATTR_IP] = { .type = NLA_NESTED },
  567 + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
  568 + [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
  569 + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  570 + [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
  571 + },
  572 + .me = THIS_MODULE,
  573 +};
  574 +
  575 +static int __init
  576 +bitmap_ip_init(void)
  577 +{
  578 + return ip_set_type_register(&bitmap_ip_type);
  579 +}
  580 +
  581 +static void __exit
  582 +bitmap_ip_fini(void)
  583 +{
  584 + ip_set_type_unregister(&bitmap_ip_type);
  585 +}
  586 +
  587 +module_init(bitmap_ip_init);
  588 +module_exit(bitmap_ip_fini);