~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to net/netfilter/ipset/ip_set_hash_netiface.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
 
2
 *
 
3
 * This program is free software; you can redistribute it and/or modify
 
4
 * it under the terms of the GNU General Public License version 2 as
 
5
 * published by the Free Software Foundation.
 
6
 */
 
7
 
 
8
/* Kernel module implementing an IP set type: the hash:net,iface type */
 
9
 
 
10
#include <linux/jhash.h>
 
11
#include <linux/module.h>
 
12
#include <linux/ip.h>
 
13
#include <linux/skbuff.h>
 
14
#include <linux/errno.h>
 
15
#include <linux/random.h>
 
16
#include <linux/rbtree.h>
 
17
#include <net/ip.h>
 
18
#include <net/ipv6.h>
 
19
#include <net/netlink.h>
 
20
 
 
21
#include <linux/netfilter.h>
 
22
#include <linux/netfilter/ipset/pfxlen.h>
 
23
#include <linux/netfilter/ipset/ip_set.h>
 
24
#include <linux/netfilter/ipset/ip_set_timeout.h>
 
25
#include <linux/netfilter/ipset/ip_set_hash.h>
 
26
 
 
27
MODULE_LICENSE("GPL");
 
28
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 
29
MODULE_DESCRIPTION("hash:net,iface type of IP sets");
 
30
MODULE_ALIAS("ip_set_hash:net,iface");
 
31
 
 
32
/* Interface name rbtree */
 
33
 
 
34
struct iface_node {
 
35
        struct rb_node node;
 
36
        char iface[IFNAMSIZ];
 
37
};
 
38
 
 
39
#define iface_data(n)   (rb_entry(n, struct iface_node, node)->iface)
 
40
 
 
41
static inline long
 
42
ifname_compare(const char *_a, const char *_b)
 
43
{
 
44
        const long *a = (const long *)_a;
 
45
        const long *b = (const long *)_b;
 
46
 
 
47
        BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
 
48
        if (a[0] != b[0])
 
49
                return a[0] - b[0];
 
50
        if (IFNAMSIZ > sizeof(long)) {
 
51
                if (a[1] != b[1])
 
52
                        return a[1] - b[1];
 
53
        }
 
54
        if (IFNAMSIZ > 2 * sizeof(long)) {
 
55
                if (a[2] != b[2])
 
56
                        return a[2] - b[2];
 
57
        }
 
58
        if (IFNAMSIZ > 3 * sizeof(long)) {
 
59
                if (a[3] != b[3])
 
60
                        return a[3] - b[3];
 
61
        }
 
62
        return 0;
 
63
}
 
64
 
 
65
static void
 
66
rbtree_destroy(struct rb_root *root)
 
67
{
 
68
        struct rb_node *p, *n = root->rb_node;
 
69
        struct iface_node *node;
 
70
 
 
71
        /* Non-recursive destroy, like in ext3 */
 
72
        while (n) {
 
73
                if (n->rb_left) {
 
74
                        n = n->rb_left;
 
75
                        continue;
 
76
                }
 
77
                if (n->rb_right) {
 
78
                        n = n->rb_right;
 
79
                        continue;
 
80
                }
 
81
                p = rb_parent(n);
 
82
                node = rb_entry(n, struct iface_node, node);
 
83
                if (!p)
 
84
                        *root = RB_ROOT;
 
85
                else if (p->rb_left == n)
 
86
                        p->rb_left = NULL;
 
87
                else if (p->rb_right == n)
 
88
                        p->rb_right = NULL;
 
89
 
 
90
                kfree(node);
 
91
                n = p;
 
92
        }
 
93
}
 
94
 
 
95
static int
 
96
iface_test(struct rb_root *root, const char **iface)
 
97
{
 
98
        struct rb_node *n = root->rb_node;
 
99
 
 
100
        while (n) {
 
101
                const char *d = iface_data(n);
 
102
                long res = ifname_compare(*iface, d);
 
103
 
 
104
                if (res < 0)
 
105
                        n = n->rb_left;
 
106
                else if (res > 0)
 
107
                        n = n->rb_right;
 
108
                else {
 
109
                        *iface = d;
 
110
                        return 1;
 
111
                }
 
112
        }
 
113
        return 0;
 
114
}
 
115
 
 
116
static int
 
117
iface_add(struct rb_root *root, const char **iface)
 
118
{
 
119
        struct rb_node **n = &(root->rb_node), *p = NULL;
 
120
        struct iface_node *d;
 
121
 
 
122
        while (*n) {
 
123
                char *ifname = iface_data(*n);
 
124
                long res = ifname_compare(*iface, ifname);
 
125
 
 
126
                p = *n;
 
127
                if (res < 0)
 
128
                        n = &((*n)->rb_left);
 
129
                else if (res > 0)
 
130
                        n = &((*n)->rb_right);
 
131
                else {
 
132
                        *iface = ifname;
 
133
                        return 0;
 
134
                }
 
135
        }
 
136
 
 
137
        d = kzalloc(sizeof(*d), GFP_ATOMIC);
 
138
        if (!d)
 
139
                return -ENOMEM;
 
140
        strcpy(d->iface, *iface);
 
141
 
 
142
        rb_link_node(&d->node, p, n);
 
143
        rb_insert_color(&d->node, root);
 
144
 
 
145
        *iface = d->iface;
 
146
        return 0;
 
147
}
 
148
 
 
149
/* Type specific function prefix */
 
150
#define TYPE            hash_netiface
 
151
 
 
152
static bool
 
153
hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b);
 
154
 
 
155
#define hash_netiface4_same_set hash_netiface_same_set
 
156
#define hash_netiface6_same_set hash_netiface_same_set
 
157
 
 
158
#define STREQ(a, b)     (strcmp(a, b) == 0)
 
159
 
 
160
/* The type variant functions: IPv4 */
 
161
 
 
162
struct hash_netiface4_elem_hashed {
 
163
        __be32 ip;
 
164
        u8 physdev;
 
165
        u8 cidr;
 
166
        u16 padding;
 
167
};
 
168
 
 
169
#define HKEY_DATALEN    sizeof(struct hash_netiface4_elem_hashed)
 
170
 
 
171
/* Member elements without timeout */
 
172
struct hash_netiface4_elem {
 
173
        __be32 ip;
 
174
        u8 physdev;
 
175
        u8 cidr;
 
176
        u16 padding;
 
177
        const char *iface;
 
178
};
 
179
 
 
180
/* Member elements with timeout support */
 
181
struct hash_netiface4_telem {
 
182
        __be32 ip;
 
183
        u8 physdev;
 
184
        u8 cidr;
 
185
        u16 padding;
 
186
        const char *iface;
 
187
        unsigned long timeout;
 
188
};
 
189
 
 
190
static inline bool
 
191
hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
 
192
                          const struct hash_netiface4_elem *ip2,
 
193
                          u32 *multi)
 
194
{
 
195
        return ip1->ip == ip2->ip &&
 
196
               ip1->cidr == ip2->cidr &&
 
197
               (++*multi) &&
 
198
               ip1->physdev == ip2->physdev &&
 
199
               ip1->iface == ip2->iface;
 
200
}
 
201
 
 
202
static inline bool
 
203
hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
 
204
{
 
205
        return elem->cidr == 0;
 
206
}
 
207
 
 
208
static inline void
 
209
hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
 
210
                         const struct hash_netiface4_elem *src) {
 
211
        dst->ip = src->ip;
 
212
        dst->cidr = src->cidr;
 
213
        dst->physdev = src->physdev;
 
214
        dst->iface = src->iface;
 
215
}
 
216
 
 
217
static inline void
 
218
hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
 
219
{
 
220
        elem->ip &= ip_set_netmask(cidr);
 
221
        elem->cidr = cidr;
 
222
}
 
223
 
 
224
static inline void
 
225
hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
 
226
{
 
227
        elem->cidr = 0;
 
228
}
 
229
 
 
230
static bool
 
231
hash_netiface4_data_list(struct sk_buff *skb,
 
232
                         const struct hash_netiface4_elem *data)
 
233
{
 
234
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
235
 
 
236
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
 
237
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
 
238
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
 
239
        if (flags)
 
240
                NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
 
241
        return 0;
 
242
 
 
243
nla_put_failure:
 
244
        return 1;
 
245
}
 
246
 
 
247
static bool
 
248
hash_netiface4_data_tlist(struct sk_buff *skb,
 
249
                          const struct hash_netiface4_elem *data)
 
250
{
 
251
        const struct hash_netiface4_telem *tdata =
 
252
                (const struct hash_netiface4_telem *)data;
 
253
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
254
 
 
255
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
 
256
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
 
257
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
 
258
        if (flags)
 
259
                NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
 
260
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
 
261
                      htonl(ip_set_timeout_get(tdata->timeout)));
 
262
 
 
263
        return 0;
 
264
 
 
265
nla_put_failure:
 
266
        return 1;
 
267
}
 
268
 
 
269
#define IP_SET_HASH_WITH_NETS
 
270
#define IP_SET_HASH_WITH_RBTREE
 
271
#define IP_SET_HASH_WITH_MULTI
 
272
 
 
273
#define PF              4
 
274
#define HOST_MASK       32
 
275
#include <linux/netfilter/ipset/ip_set_ahash.h>
 
276
 
 
277
static inline void
 
278
hash_netiface4_data_next(struct ip_set_hash *h,
 
279
                         const struct hash_netiface4_elem *d)
 
280
{
 
281
        h->next.ip = ntohl(d->ip);
 
282
}
 
283
 
 
284
static int
 
285
hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
 
286
                    const struct xt_action_param *par,
 
287
                    enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 
288
{
 
289
        struct ip_set_hash *h = set->data;
 
290
        ipset_adtfn adtfn = set->variant->adt[adt];
 
291
        struct hash_netiface4_elem data = {
 
292
                .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
 
293
        };
 
294
        int ret;
 
295
 
 
296
        if (data.cidr == 0)
 
297
                return -EINVAL;
 
298
        if (adt == IPSET_TEST)
 
299
                data.cidr = HOST_MASK;
 
300
 
 
301
        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
 
302
        data.ip &= ip_set_netmask(data.cidr);
 
303
 
 
304
#define IFACE(dir)      (par->dir ? par->dir->name : NULL)
 
305
#define PHYSDEV(dir)    (nf_bridge->dir ? nf_bridge->dir->name : NULL)
 
306
#define SRCDIR          (opt->flags & IPSET_DIM_TWO_SRC)
 
307
 
 
308
        if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 
309
#ifdef CONFIG_BRIDGE_NETFILTER
 
310
                const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 
311
 
 
312
                if (!nf_bridge)
 
313
                        return -EINVAL;
 
314
                data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
 
315
                data.physdev = 1;
 
316
#else
 
317
                data.iface = NULL;
 
318
#endif
 
319
        } else
 
320
                data.iface = SRCDIR ? IFACE(in) : IFACE(out);
 
321
 
 
322
        if (!data.iface)
 
323
                return -EINVAL;
 
324
        ret = iface_test(&h->rbtree, &data.iface);
 
325
        if (adt == IPSET_ADD) {
 
326
                if (!ret) {
 
327
                        ret = iface_add(&h->rbtree, &data.iface);
 
328
                        if (ret)
 
329
                                return ret;
 
330
                }
 
331
        } else if (!ret)
 
332
                return ret;
 
333
 
 
334
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 
335
}
 
336
 
 
337
static int
 
338
hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 
339
                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 
340
{
 
341
        struct ip_set_hash *h = set->data;
 
342
        ipset_adtfn adtfn = set->variant->adt[adt];
 
343
        struct hash_netiface4_elem data = { .cidr = HOST_MASK };
 
344
        u32 ip = 0, ip_to, last;
 
345
        u32 timeout = h->timeout;
 
346
        char iface[IFNAMSIZ] = {};
 
347
        int ret;
 
348
 
 
349
        if (unlikely(!tb[IPSET_ATTR_IP] ||
 
350
                     !tb[IPSET_ATTR_IFACE] ||
 
351
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 
352
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 
353
                return -IPSET_ERR_PROTOCOL;
 
354
 
 
355
        if (tb[IPSET_ATTR_LINENO])
 
356
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
357
 
 
358
        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
 
359
        if (ret)
 
360
                return ret;
 
361
 
 
362
        if (tb[IPSET_ATTR_CIDR]) {
 
363
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 
364
                if (!data.cidr)
 
365
                        return -IPSET_ERR_INVALID_CIDR;
 
366
        }
 
367
 
 
368
        if (tb[IPSET_ATTR_TIMEOUT]) {
 
369
                if (!with_timeout(h->timeout))
 
370
                        return -IPSET_ERR_TIMEOUT;
 
371
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
372
        }
 
373
 
 
374
        strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
 
375
        data.iface = iface;
 
376
        ret = iface_test(&h->rbtree, &data.iface);
 
377
        if (adt == IPSET_ADD) {
 
378
                if (!ret) {
 
379
                        ret = iface_add(&h->rbtree, &data.iface);
 
380
                        if (ret)
 
381
                                return ret;
 
382
                }
 
383
        } else if (!ret)
 
384
                return ret;
 
385
 
 
386
        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 
387
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 
388
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
 
389
                        data.physdev = 1;
 
390
        }
 
391
 
 
392
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
 
393
                data.ip = htonl(ip & ip_set_hostmask(data.cidr));
 
394
                ret = adtfn(set, &data, timeout, flags);
 
395
                return ip_set_eexist(ret, flags) ? 0 : ret;
 
396
        }
 
397
 
 
398
        if (tb[IPSET_ATTR_IP_TO]) {
 
399
                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 
400
                if (ret)
 
401
                        return ret;
 
402
                if (ip_to < ip)
 
403
                        swap(ip, ip_to);
 
404
                if (ip + UINT_MAX == ip_to)
 
405
                        return -IPSET_ERR_HASH_RANGE;
 
406
        } else {
 
407
                ip_set_mask_from_to(ip, ip_to, data.cidr);
 
408
        }
 
409
 
 
410
        if (retried)
 
411
                ip = h->next.ip;
 
412
        while (!after(ip, ip_to)) {
 
413
                data.ip = htonl(ip);
 
414
                last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
 
415
                ret = adtfn(set, &data, timeout, flags);
 
416
 
 
417
                if (ret && !ip_set_eexist(ret, flags))
 
418
                        return ret;
 
419
                else
 
420
                        ret = 0;
 
421
                ip = last + 1;
 
422
        }
 
423
        return ret;
 
424
}
 
425
 
 
426
static bool
 
427
hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b)
 
428
{
 
429
        const struct ip_set_hash *x = a->data;
 
430
        const struct ip_set_hash *y = b->data;
 
431
 
 
432
        /* Resizing changes htable_bits, so we ignore it */
 
433
        return x->maxelem == y->maxelem &&
 
434
               x->timeout == y->timeout;
 
435
}
 
436
 
 
437
/* The type variant functions: IPv6 */
 
438
 
 
439
struct hash_netiface6_elem_hashed {
 
440
        union nf_inet_addr ip;
 
441
        u8 physdev;
 
442
        u8 cidr;
 
443
        u16 padding;
 
444
};
 
445
 
 
446
#define HKEY_DATALEN    sizeof(struct hash_netiface6_elem_hashed)
 
447
 
 
448
struct hash_netiface6_elem {
 
449
        union nf_inet_addr ip;
 
450
        u8 physdev;
 
451
        u8 cidr;
 
452
        u16 padding;
 
453
        const char *iface;
 
454
};
 
455
 
 
456
struct hash_netiface6_telem {
 
457
        union nf_inet_addr ip;
 
458
        u8 physdev;
 
459
        u8 cidr;
 
460
        u16 padding;
 
461
        const char *iface;
 
462
        unsigned long timeout;
 
463
};
 
464
 
 
465
static inline bool
 
466
hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
 
467
                          const struct hash_netiface6_elem *ip2,
 
468
                          u32 *multi)
 
469
{
 
470
        return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
 
471
               ip1->cidr == ip2->cidr &&
 
472
               (++*multi) &&
 
473
               ip1->physdev == ip2->physdev &&
 
474
               ip1->iface == ip2->iface;
 
475
}
 
476
 
 
477
static inline bool
 
478
hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
 
479
{
 
480
        return elem->cidr == 0;
 
481
}
 
482
 
 
483
static inline void
 
484
hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
 
485
                         const struct hash_netiface6_elem *src)
 
486
{
 
487
        memcpy(dst, src, sizeof(*dst));
 
488
}
 
489
 
 
490
static inline void
 
491
hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
 
492
{
 
493
}
 
494
 
 
495
static inline void
 
496
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
 
497
{
 
498
        ip->ip6[0] &= ip_set_netmask6(prefix)[0];
 
499
        ip->ip6[1] &= ip_set_netmask6(prefix)[1];
 
500
        ip->ip6[2] &= ip_set_netmask6(prefix)[2];
 
501
        ip->ip6[3] &= ip_set_netmask6(prefix)[3];
 
502
}
 
503
 
 
504
static inline void
 
505
hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
 
506
{
 
507
        ip6_netmask(&elem->ip, cidr);
 
508
        elem->cidr = cidr;
 
509
}
 
510
 
 
511
static bool
 
512
hash_netiface6_data_list(struct sk_buff *skb,
 
513
                         const struct hash_netiface6_elem *data)
 
514
{
 
515
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
516
 
 
517
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
 
518
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
 
519
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
 
520
        if (flags)
 
521
                NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
 
522
        return 0;
 
523
 
 
524
nla_put_failure:
 
525
        return 1;
 
526
}
 
527
 
 
528
static bool
 
529
hash_netiface6_data_tlist(struct sk_buff *skb,
 
530
                          const struct hash_netiface6_elem *data)
 
531
{
 
532
        const struct hash_netiface6_telem *e =
 
533
                (const struct hash_netiface6_telem *)data;
 
534
        u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
 
535
 
 
536
        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
 
537
        NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
 
538
        NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
 
539
        if (flags)
 
540
                NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
 
541
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
 
542
                      htonl(ip_set_timeout_get(e->timeout)));
 
543
        return 0;
 
544
 
 
545
nla_put_failure:
 
546
        return 1;
 
547
}
 
548
 
 
549
#undef PF
 
550
#undef HOST_MASK
 
551
 
 
552
#define PF              6
 
553
#define HOST_MASK       128
 
554
#include <linux/netfilter/ipset/ip_set_ahash.h>
 
555
 
 
556
static inline void
 
557
hash_netiface6_data_next(struct ip_set_hash *h,
 
558
                         const struct hash_netiface6_elem *d)
 
559
{
 
560
}
 
561
 
 
562
static int
 
563
hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
 
564
                    const struct xt_action_param *par,
 
565
                    enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 
566
{
 
567
        struct ip_set_hash *h = set->data;
 
568
        ipset_adtfn adtfn = set->variant->adt[adt];
 
569
        struct hash_netiface6_elem data = {
 
570
                .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
 
571
        };
 
572
        int ret;
 
573
 
 
574
        if (data.cidr == 0)
 
575
                return -EINVAL;
 
576
        if (adt == IPSET_TEST)
 
577
                data.cidr = HOST_MASK;
 
578
 
 
579
        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
 
580
        ip6_netmask(&data.ip, data.cidr);
 
581
 
 
582
        if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 
583
#ifdef CONFIG_BRIDGE_NETFILTER
 
584
                const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 
585
 
 
586
                if (!nf_bridge)
 
587
                        return -EINVAL;
 
588
                data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
 
589
                data.physdev = 1;
 
590
#else
 
591
                data.iface = NULL;
 
592
#endif
 
593
        } else
 
594
                data.iface = SRCDIR ? IFACE(in) : IFACE(out);
 
595
 
 
596
        if (!data.iface)
 
597
                return -EINVAL;
 
598
        ret = iface_test(&h->rbtree, &data.iface);
 
599
        if (adt == IPSET_ADD) {
 
600
                if (!ret) {
 
601
                        ret = iface_add(&h->rbtree, &data.iface);
 
602
                        if (ret)
 
603
                                return ret;
 
604
                }
 
605
        } else if (!ret)
 
606
                return ret;
 
607
 
 
608
        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 
609
}
 
610
 
 
611
static int
 
612
hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 
613
                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 
614
{
 
615
        struct ip_set_hash *h = set->data;
 
616
        ipset_adtfn adtfn = set->variant->adt[adt];
 
617
        struct hash_netiface6_elem data = { .cidr = HOST_MASK };
 
618
        u32 timeout = h->timeout;
 
619
        char iface[IFNAMSIZ] = {};
 
620
        int ret;
 
621
 
 
622
        if (unlikely(!tb[IPSET_ATTR_IP] ||
 
623
                     !tb[IPSET_ATTR_IFACE] ||
 
624
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 
625
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 
626
                return -IPSET_ERR_PROTOCOL;
 
627
        if (unlikely(tb[IPSET_ATTR_IP_TO]))
 
628
                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 
629
 
 
630
        if (tb[IPSET_ATTR_LINENO])
 
631
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
632
 
 
633
        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
 
634
        if (ret)
 
635
                return ret;
 
636
 
 
637
        if (tb[IPSET_ATTR_CIDR])
 
638
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 
639
        if (!data.cidr)
 
640
                return -IPSET_ERR_INVALID_CIDR;
 
641
        ip6_netmask(&data.ip, data.cidr);
 
642
 
 
643
        if (tb[IPSET_ATTR_TIMEOUT]) {
 
644
                if (!with_timeout(h->timeout))
 
645
                        return -IPSET_ERR_TIMEOUT;
 
646
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
647
        }
 
648
 
 
649
        strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
 
650
        data.iface = iface;
 
651
        ret = iface_test(&h->rbtree, &data.iface);
 
652
        if (adt == IPSET_ADD) {
 
653
                if (!ret) {
 
654
                        ret = iface_add(&h->rbtree, &data.iface);
 
655
                        if (ret)
 
656
                                return ret;
 
657
                }
 
658
        } else if (!ret)
 
659
                return ret;
 
660
 
 
661
        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 
662
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 
663
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
 
664
                        data.physdev = 1;
 
665
        }
 
666
 
 
667
        ret = adtfn(set, &data, timeout, flags);
 
668
 
 
669
        return ip_set_eexist(ret, flags) ? 0 : ret;
 
670
}
 
671
 
 
672
/* Create hash:ip type of sets */
 
673
 
 
674
static int
 
675
hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
676
{
 
677
        struct ip_set_hash *h;
 
678
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
 
679
        u8 hbits;
 
680
 
 
681
        if (!(set->family == AF_INET || set->family == AF_INET6))
 
682
                return -IPSET_ERR_INVALID_FAMILY;
 
683
 
 
684
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
 
685
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
 
686
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
 
687
                return -IPSET_ERR_PROTOCOL;
 
688
 
 
689
        if (tb[IPSET_ATTR_HASHSIZE]) {
 
690
                hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
 
691
                if (hashsize < IPSET_MIMINAL_HASHSIZE)
 
692
                        hashsize = IPSET_MIMINAL_HASHSIZE;
 
693
        }
 
694
 
 
695
        if (tb[IPSET_ATTR_MAXELEM])
 
696
                maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
 
697
 
 
698
        h = kzalloc(sizeof(*h)
 
699
                    + sizeof(struct ip_set_hash_nets)
 
700
                      * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
 
701
        if (!h)
 
702
                return -ENOMEM;
 
703
 
 
704
        h->maxelem = maxelem;
 
705
        get_random_bytes(&h->initval, sizeof(h->initval));
 
706
        h->timeout = IPSET_NO_TIMEOUT;
 
707
        h->ahash_max = AHASH_MAX_SIZE;
 
708
 
 
709
        hbits = htable_bits(hashsize);
 
710
        h->table = ip_set_alloc(
 
711
                        sizeof(struct htable)
 
712
                        + jhash_size(hbits) * sizeof(struct hbucket));
 
713
        if (!h->table) {
 
714
                kfree(h);
 
715
                return -ENOMEM;
 
716
        }
 
717
        h->table->htable_bits = hbits;
 
718
        h->rbtree = RB_ROOT;
 
719
 
 
720
        set->data = h;
 
721
 
 
722
        if (tb[IPSET_ATTR_TIMEOUT]) {
 
723
                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
724
 
 
725
                set->variant = set->family == AF_INET
 
726
                        ? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
 
727
 
 
728
                if (set->family == AF_INET)
 
729
                        hash_netiface4_gc_init(set);
 
730
                else
 
731
                        hash_netiface6_gc_init(set);
 
732
        } else {
 
733
                set->variant = set->family == AF_INET
 
734
                        ? &hash_netiface4_variant : &hash_netiface6_variant;
 
735
        }
 
736
 
 
737
        pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
 
738
                 set->name, jhash_size(h->table->htable_bits),
 
739
                 h->table->htable_bits, h->maxelem, set->data, h->table);
 
740
 
 
741
        return 0;
 
742
}
 
743
 
 
744
static struct ip_set_type hash_netiface_type __read_mostly = {
 
745
        .name           = "hash:net,iface",
 
746
        .protocol       = IPSET_PROTOCOL,
 
747
        .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
 
748
        .dimension      = IPSET_DIM_TWO,
 
749
        .family         = AF_UNSPEC,
 
750
        .revision_min   = 0,
 
751
        .create         = hash_netiface_create,
 
752
        .create_policy  = {
 
753
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 
754
                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 
755
                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 
756
                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 
757
                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
 
758
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 
759
        },
 
760
        .adt_policy     = {
 
761
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 
762
                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 
763
                [IPSET_ATTR_IFACE]      = { .type = NLA_NUL_STRING,
 
764
                                            .len = IPSET_MAXNAMELEN - 1 },
 
765
                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 
766
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 
767
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 
768
                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 
769
        },
 
770
        .me             = THIS_MODULE,
 
771
};
 
772
 
 
773
static int __init
 
774
hash_netiface_init(void)
 
775
{
 
776
        return ip_set_type_register(&hash_netiface_type);
 
777
}
 
778
 
 
779
static void __exit
 
780
hash_netiface_fini(void)
 
781
{
 
782
        ip_set_type_unregister(&hash_netiface_type);
 
783
}
 
784
 
 
785
module_init(hash_netiface_init);
 
786
module_exit(hash_netiface_fini);