Commit 01e6de64d9c8d0e75dca3bb4cf898db73abe00d4
Exists in
master
and in
39 other branches
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Showing 33 changed files Side-by-side Diff
- include/linux/netfilter/x_tables.h
- include/net/netfilter/nf_conntrack.h
- include/net/netfilter/nf_conntrack_helper.h
- include/net/netfilter/nf_conntrack_l3proto.h
- include/net/netfilter/nf_conntrack_l4proto.h
- include/net/netfilter/nf_conntrack_tuple.h
- include/net/netlink.h
- include/net/netns/conntrack.h
- lib/nlattr.c
- net/ipv4/netfilter/arp_tables.c
- net/ipv4/netfilter/ip_tables.c
- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
- net/ipv4/netfilter/nf_conntrack_proto_icmp.c
- net/ipv4/netfilter/nf_nat_core.c
- net/ipv6/netfilter/ip6_tables.c
- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
- net/netfilter/Kconfig
- net/netfilter/nf_conntrack_core.c
- net/netfilter/nf_conntrack_expect.c
- net/netfilter/nf_conntrack_helper.c
- net/netfilter/nf_conntrack_netlink.c
- net/netfilter/nf_conntrack_proto.c
- net/netfilter/nf_conntrack_proto_dccp.c
- net/netfilter/nf_conntrack_proto_gre.c
- net/netfilter/nf_conntrack_proto_sctp.c
- net/netfilter/nf_conntrack_proto_tcp.c
- net/netfilter/nf_conntrack_proto_udp.c
- net/netfilter/nf_conntrack_proto_udplite.c
- net/netfilter/nf_conntrack_standalone.c
- net/netfilter/xt_connlimit.c
- net/netfilter/xt_physdev.c
include/linux/netfilter/x_tables.h
... | ... | @@ -437,6 +437,29 @@ |
437 | 437 | extern void xt_table_entry_swap_rcu(struct xt_table_info *old, |
438 | 438 | struct xt_table_info *new); |
439 | 439 | |
440 | +/* | |
441 | + * This helper is performance critical and must be inlined | |
442 | + */ | |
443 | +static inline unsigned long ifname_compare_aligned(const char *_a, | |
444 | + const char *_b, | |
445 | + const char *_mask) | |
446 | +{ | |
447 | + const unsigned long *a = (const unsigned long *)_a; | |
448 | + const unsigned long *b = (const unsigned long *)_b; | |
449 | + const unsigned long *mask = (const unsigned long *)_mask; | |
450 | + unsigned long ret; | |
451 | + | |
452 | + ret = (a[0] ^ b[0]) & mask[0]; | |
453 | + if (IFNAMSIZ > sizeof(unsigned long)) | |
454 | + ret |= (a[1] ^ b[1]) & mask[1]; | |
455 | + if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
456 | + ret |= (a[2] ^ b[2]) & mask[2]; | |
457 | + if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
458 | + ret |= (a[3] ^ b[3]) & mask[3]; | |
459 | + BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
460 | + return ret; | |
461 | +} | |
462 | + | |
440 | 463 | #ifdef CONFIG_COMPAT |
441 | 464 | #include <net/compat.h> |
442 | 465 |
include/net/netfilter/nf_conntrack.h
... | ... | @@ -91,8 +91,7 @@ |
91 | 91 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
92 | 92 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
93 | 93 | |
94 | -struct nf_conn | |
95 | -{ | |
94 | +struct nf_conn { | |
96 | 95 | /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, |
97 | 96 | plus 1 for any connection(s) we are `master' for */ |
98 | 97 | struct nf_conntrack ct_general; |
... | ... | @@ -126,7 +125,6 @@ |
126 | 125 | #ifdef CONFIG_NET_NS |
127 | 126 | struct net *ct_net; |
128 | 127 | #endif |
129 | - struct rcu_head rcu; | |
130 | 128 | }; |
131 | 129 | |
132 | 130 | static inline struct nf_conn * |
... | ... | @@ -190,9 +188,13 @@ |
190 | 188 | extern int nf_ct_l3proto_try_module_get(unsigned short l3proto); |
191 | 189 | extern void nf_ct_l3proto_module_put(unsigned short l3proto); |
192 | 190 | |
193 | -extern struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced); | |
194 | -extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, | |
195 | - unsigned int size); | |
191 | +/* | |
192 | + * Allocate a hashtable of hlist_head (if nulls == 0), | |
193 | + * or hlist_nulls_head (if nulls == 1) | |
194 | + */ | |
195 | +extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls); | |
196 | + | |
197 | +extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); | |
196 | 198 | |
197 | 199 | extern struct nf_conntrack_tuple_hash * |
198 | 200 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); |
include/net/netfilter/nf_conntrack_helper.h
include/net/netfilter/nf_conntrack_l3proto.h
... | ... | @@ -53,9 +53,16 @@ |
53 | 53 | int (*tuple_to_nlattr)(struct sk_buff *skb, |
54 | 54 | const struct nf_conntrack_tuple *t); |
55 | 55 | |
56 | + /* | |
57 | + * Calculate size of tuple nlattr | |
58 | + */ | |
59 | + int (*nlattr_tuple_size)(void); | |
60 | + | |
56 | 61 | int (*nlattr_to_tuple)(struct nlattr *tb[], |
57 | 62 | struct nf_conntrack_tuple *t); |
58 | 63 | const struct nla_policy *nla_policy; |
64 | + | |
65 | + size_t nla_size; | |
59 | 66 | |
60 | 67 | #ifdef CONFIG_SYSCTL |
61 | 68 | struct ctl_table_header *ctl_table_header; |
include/net/netfilter/nf_conntrack_l4proto.h
... | ... | @@ -64,16 +64,22 @@ |
64 | 64 | /* convert protoinfo to nfnetink attributes */ |
65 | 65 | int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, |
66 | 66 | const struct nf_conn *ct); |
67 | + /* Calculate protoinfo nlattr size */ | |
68 | + int (*nlattr_size)(void); | |
67 | 69 | |
68 | 70 | /* convert nfnetlink attributes to protoinfo */ |
69 | 71 | int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); |
70 | 72 | |
71 | 73 | int (*tuple_to_nlattr)(struct sk_buff *skb, |
72 | 74 | const struct nf_conntrack_tuple *t); |
75 | + /* Calculate tuple nlattr size */ | |
76 | + int (*nlattr_tuple_size)(void); | |
73 | 77 | int (*nlattr_to_tuple)(struct nlattr *tb[], |
74 | 78 | struct nf_conntrack_tuple *t); |
75 | 79 | const struct nla_policy *nla_policy; |
76 | 80 | |
81 | + size_t nla_size; | |
82 | + | |
77 | 83 | #ifdef CONFIG_SYSCTL |
78 | 84 | struct ctl_table_header **ctl_table_header; |
79 | 85 | struct ctl_table *ctl_table; |
... | ... | @@ -107,6 +113,7 @@ |
107 | 113 | const struct nf_conntrack_tuple *tuple); |
108 | 114 | extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], |
109 | 115 | struct nf_conntrack_tuple *t); |
116 | +extern int nf_ct_port_nlattr_tuple_size(void); | |
110 | 117 | extern const struct nla_policy nf_ct_port_nla_policy[]; |
111 | 118 | |
112 | 119 | #ifdef CONFIG_SYSCTL |
include/net/netfilter/nf_conntrack_tuple.h
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | |
13 | 13 | #include <linux/netfilter/x_tables.h> |
14 | 14 | #include <linux/netfilter/nf_conntrack_tuple_common.h> |
15 | +#include <linux/list_nulls.h> | |
15 | 16 | |
16 | 17 | /* A `tuple' is a structure containing the information to uniquely |
17 | 18 | identify a connection. ie. if two packets have the same tuple, they |
... | ... | @@ -146,9 +147,8 @@ |
146 | 147 | ((enum ip_conntrack_dir)(h)->tuple.dst.dir) |
147 | 148 | |
148 | 149 | /* Connections have two entries in the hash table: one for each way */ |
149 | -struct nf_conntrack_tuple_hash | |
150 | -{ | |
151 | - struct hlist_node hnode; | |
150 | +struct nf_conntrack_tuple_hash { | |
151 | + struct hlist_nulls_node hnnode; | |
152 | 152 | struct nf_conntrack_tuple tuple; |
153 | 153 | }; |
154 | 154 |
include/net/netlink.h
... | ... | @@ -230,6 +230,7 @@ |
230 | 230 | extern int nla_parse(struct nlattr *tb[], int maxtype, |
231 | 231 | struct nlattr *head, int len, |
232 | 232 | const struct nla_policy *policy); |
233 | +extern int nla_policy_len(const struct nla_policy *, int); | |
233 | 234 | extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); |
234 | 235 | extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, |
235 | 236 | size_t dstsize); |
include/net/netns/conntrack.h
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | #define __NETNS_CONNTRACK_H |
3 | 3 | |
4 | 4 | #include <linux/list.h> |
5 | +#include <linux/list_nulls.h> | |
5 | 6 | #include <asm/atomic.h> |
6 | 7 | |
7 | 8 | struct ctl_table_header; |
8 | 9 | |
... | ... | @@ -10,9 +11,9 @@ |
10 | 11 | struct netns_ct { |
11 | 12 | atomic_t count; |
12 | 13 | unsigned int expect_count; |
13 | - struct hlist_head *hash; | |
14 | + struct hlist_nulls_head *hash; | |
14 | 15 | struct hlist_head *expect_hash; |
15 | - struct hlist_head unconfirmed; | |
16 | + struct hlist_nulls_head unconfirmed; | |
16 | 17 | struct ip_conntrack_stat *stat; |
17 | 18 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
18 | 19 | struct nf_conntrack_ecache *ecache; |
lib/nlattr.c
... | ... | @@ -133,6 +133,32 @@ |
133 | 133 | } |
134 | 134 | |
135 | 135 | /** |
136 | + * nla_policy_len - Determin the max. length of a policy | |
137 | + * @policy: policy to use | |
138 | + * @n: number of policies | |
139 | + * | |
140 | + * Determines the max. length of the policy. It is currently used | |
141 | + * to allocated Netlink buffers roughly the size of the actual | |
142 | + * message. | |
143 | + * | |
144 | + * Returns 0 on success or a negative error code. | |
145 | + */ | |
146 | +int | |
147 | +nla_policy_len(const struct nla_policy *p, int n) | |
148 | +{ | |
149 | + int i, len = 0; | |
150 | + | |
151 | + for (i = 0; i < n; i++) { | |
152 | + if (p->len) | |
153 | + len += nla_total_size(p->len); | |
154 | + else if (nla_attr_minlen[p->type]) | |
155 | + len += nla_total_size(nla_attr_minlen[p->type]); | |
156 | + } | |
157 | + | |
158 | + return len; | |
159 | +} | |
160 | + | |
161 | +/** | |
136 | 162 | * nla_parse - Parse a stream of attributes into a tb buffer |
137 | 163 | * @tb: destination array with maxtype+1 elements |
138 | 164 | * @maxtype: maximum attribute type to be expected |
... | ... | @@ -467,6 +493,7 @@ |
467 | 493 | #endif |
468 | 494 | |
469 | 495 | EXPORT_SYMBOL(nla_validate); |
496 | +EXPORT_SYMBOL(nla_policy_len); | |
470 | 497 | EXPORT_SYMBOL(nla_parse); |
471 | 498 | EXPORT_SYMBOL(nla_find); |
472 | 499 | EXPORT_SYMBOL(nla_strlcpy); |
net/ipv4/netfilter/arp_tables.c
... | ... | @@ -81,19 +81,7 @@ |
81 | 81 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) |
82 | 82 | { |
83 | 83 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
84 | - const unsigned long *a = (const unsigned long *)_a; | |
85 | - const unsigned long *b = (const unsigned long *)_b; | |
86 | - const unsigned long *mask = (const unsigned long *)_mask; | |
87 | - unsigned long ret; | |
88 | - | |
89 | - ret = (a[0] ^ b[0]) & mask[0]; | |
90 | - if (IFNAMSIZ > sizeof(unsigned long)) | |
91 | - ret |= (a[1] ^ b[1]) & mask[1]; | |
92 | - if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
93 | - ret |= (a[2] ^ b[2]) & mask[2]; | |
94 | - if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
95 | - ret |= (a[3] ^ b[3]) & mask[3]; | |
96 | - BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
84 | + unsigned long ret = ifname_compare_aligned(_a, _b, _mask); | |
97 | 85 | #else |
98 | 86 | unsigned long ret = 0; |
99 | 87 | const u16 *a = (const u16 *)_a; |
... | ... | @@ -404,7 +392,9 @@ |
404 | 392 | && unconditional(&e->arp)) || visited) { |
405 | 393 | unsigned int oldpos, size; |
406 | 394 | |
407 | - if (t->verdict < -NF_MAX_VERDICT - 1) { | |
395 | + if ((strcmp(t->target.u.user.name, | |
396 | + ARPT_STANDARD_TARGET) == 0) && | |
397 | + t->verdict < -NF_MAX_VERDICT - 1) { | |
408 | 398 | duprintf("mark_source_chains: bad " |
409 | 399 | "negative verdict (%i)\n", |
410 | 400 | t->verdict); |
net/ipv4/netfilter/ip_tables.c
... | ... | @@ -74,25 +74,6 @@ |
74 | 74 | |
75 | 75 | Hence the start of any table is given by get_table() below. */ |
76 | 76 | |
77 | -static unsigned long ifname_compare(const char *_a, const char *_b, | |
78 | - const unsigned char *_mask) | |
79 | -{ | |
80 | - const unsigned long *a = (const unsigned long *)_a; | |
81 | - const unsigned long *b = (const unsigned long *)_b; | |
82 | - const unsigned long *mask = (const unsigned long *)_mask; | |
83 | - unsigned long ret; | |
84 | - | |
85 | - ret = (a[0] ^ b[0]) & mask[0]; | |
86 | - if (IFNAMSIZ > sizeof(unsigned long)) | |
87 | - ret |= (a[1] ^ b[1]) & mask[1]; | |
88 | - if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
89 | - ret |= (a[2] ^ b[2]) & mask[2]; | |
90 | - if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
91 | - ret |= (a[3] ^ b[3]) & mask[3]; | |
92 | - BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
93 | - return ret; | |
94 | -} | |
95 | - | |
96 | 77 | /* Returns whether matches rule or not. */ |
97 | 78 | /* Performance critical - called for every packet */ |
98 | 79 | static inline bool |
... | ... | @@ -121,7 +102,7 @@ |
121 | 102 | return false; |
122 | 103 | } |
123 | 104 | |
124 | - ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); | |
105 | + ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask); | |
125 | 106 | |
126 | 107 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
127 | 108 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
... | ... | @@ -130,7 +111,7 @@ |
130 | 111 | return false; |
131 | 112 | } |
132 | 113 | |
133 | - ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); | |
114 | + ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask); | |
134 | 115 | |
135 | 116 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
136 | 117 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
... | ... | @@ -507,7 +488,9 @@ |
507 | 488 | && unconditional(&e->ip)) || visited) { |
508 | 489 | unsigned int oldpos, size; |
509 | 490 | |
510 | - if (t->verdict < -NF_MAX_VERDICT - 1) { | |
491 | + if ((strcmp(t->target.u.user.name, | |
492 | + IPT_STANDARD_TARGET) == 0) && | |
493 | + t->verdict < -NF_MAX_VERDICT - 1) { | |
511 | 494 | duprintf("mark_source_chains: bad " |
512 | 495 | "negative verdict (%i)\n", |
513 | 496 | t->verdict); |
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
... | ... | @@ -328,6 +328,11 @@ |
328 | 328 | |
329 | 329 | return 0; |
330 | 330 | } |
331 | + | |
332 | +static int ipv4_nlattr_tuple_size(void) | |
333 | +{ | |
334 | + return nla_policy_len(ipv4_nla_policy, CTA_IP_MAX + 1); | |
335 | +} | |
331 | 336 | #endif |
332 | 337 | |
333 | 338 | static struct nf_sockopt_ops so_getorigdst = { |
... | ... | @@ -347,6 +352,7 @@ |
347 | 352 | .get_l4proto = ipv4_get_l4proto, |
348 | 353 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
349 | 354 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, |
355 | + .nlattr_tuple_size = ipv4_nlattr_tuple_size, | |
350 | 356 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, |
351 | 357 | .nla_policy = ipv4_nla_policy, |
352 | 358 | #endif |
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
... | ... | @@ -25,40 +25,42 @@ |
25 | 25 | unsigned int bucket; |
26 | 26 | }; |
27 | 27 | |
28 | -static struct hlist_node *ct_get_first(struct seq_file *seq) | |
28 | +static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) | |
29 | 29 | { |
30 | 30 | struct net *net = seq_file_net(seq); |
31 | 31 | struct ct_iter_state *st = seq->private; |
32 | - struct hlist_node *n; | |
32 | + struct hlist_nulls_node *n; | |
33 | 33 | |
34 | 34 | for (st->bucket = 0; |
35 | 35 | st->bucket < nf_conntrack_htable_size; |
36 | 36 | st->bucket++) { |
37 | 37 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
38 | - if (n) | |
38 | + if (!is_a_nulls(n)) | |
39 | 39 | return n; |
40 | 40 | } |
41 | 41 | return NULL; |
42 | 42 | } |
43 | 43 | |
44 | -static struct hlist_node *ct_get_next(struct seq_file *seq, | |
45 | - struct hlist_node *head) | |
44 | +static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, | |
45 | + struct hlist_nulls_node *head) | |
46 | 46 | { |
47 | 47 | struct net *net = seq_file_net(seq); |
48 | 48 | struct ct_iter_state *st = seq->private; |
49 | 49 | |
50 | 50 | head = rcu_dereference(head->next); |
51 | - while (head == NULL) { | |
52 | - if (++st->bucket >= nf_conntrack_htable_size) | |
53 | - return NULL; | |
51 | + while (is_a_nulls(head)) { | |
52 | + if (likely(get_nulls_value(head) == st->bucket)) { | |
53 | + if (++st->bucket >= nf_conntrack_htable_size) | |
54 | + return NULL; | |
55 | + } | |
54 | 56 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
55 | 57 | } |
56 | 58 | return head; |
57 | 59 | } |
58 | 60 | |
59 | -static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | |
61 | +static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) | |
60 | 62 | { |
61 | - struct hlist_node *head = ct_get_first(seq); | |
63 | + struct hlist_nulls_node *head = ct_get_first(seq); | |
62 | 64 | |
63 | 65 | if (head) |
64 | 66 | while (pos && (head = ct_get_next(seq, head))) |
65 | 67 | |
66 | 68 | |
67 | 69 | |
68 | 70 | |
69 | 71 | |
70 | 72 | |
71 | 73 | |
72 | 74 | |
73 | 75 | |
74 | 76 | |
75 | 77 | |
76 | 78 | |
77 | 79 | |
78 | 80 | |
79 | 81 | |
80 | 82 | |
81 | 83 | |
... | ... | @@ -87,69 +89,76 @@ |
87 | 89 | |
88 | 90 | static int ct_seq_show(struct seq_file *s, void *v) |
89 | 91 | { |
90 | - const struct nf_conntrack_tuple_hash *hash = v; | |
91 | - const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | |
92 | + struct nf_conntrack_tuple_hash *hash = v; | |
93 | + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | |
92 | 94 | const struct nf_conntrack_l3proto *l3proto; |
93 | 95 | const struct nf_conntrack_l4proto *l4proto; |
96 | + int ret = 0; | |
94 | 97 | |
95 | 98 | NF_CT_ASSERT(ct); |
99 | + if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | |
100 | + return 0; | |
96 | 101 | |
102 | + | |
97 | 103 | /* we only want to print DIR_ORIGINAL */ |
98 | 104 | if (NF_CT_DIRECTION(hash)) |
99 | - return 0; | |
105 | + goto release; | |
100 | 106 | if (nf_ct_l3num(ct) != AF_INET) |
101 | - return 0; | |
107 | + goto release; | |
102 | 108 | |
103 | 109 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
104 | 110 | NF_CT_ASSERT(l3proto); |
105 | 111 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
106 | 112 | NF_CT_ASSERT(l4proto); |
107 | 113 | |
114 | + ret = -ENOSPC; | |
108 | 115 | if (seq_printf(s, "%-8s %u %ld ", |
109 | 116 | l4proto->name, nf_ct_protonum(ct), |
110 | 117 | timer_pending(&ct->timeout) |
111 | 118 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
112 | - return -ENOSPC; | |
119 | + goto release; | |
113 | 120 | |
114 | 121 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
115 | - return -ENOSPC; | |
122 | + goto release; | |
116 | 123 | |
117 | 124 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
118 | 125 | l3proto, l4proto)) |
119 | - return -ENOSPC; | |
126 | + goto release; | |
120 | 127 | |
121 | 128 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
122 | - return -ENOSPC; | |
129 | + goto release; | |
123 | 130 | |
124 | 131 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
125 | 132 | if (seq_printf(s, "[UNREPLIED] ")) |
126 | - return -ENOSPC; | |
133 | + goto release; | |
127 | 134 | |
128 | 135 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
129 | 136 | l3proto, l4proto)) |
130 | - return -ENOSPC; | |
137 | + goto release; | |
131 | 138 | |
132 | 139 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
133 | - return -ENOSPC; | |
140 | + goto release; | |
134 | 141 | |
135 | 142 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
136 | 143 | if (seq_printf(s, "[ASSURED] ")) |
137 | - return -ENOSPC; | |
144 | + goto release; | |
138 | 145 | |
139 | 146 | #ifdef CONFIG_NF_CONNTRACK_MARK |
140 | 147 | if (seq_printf(s, "mark=%u ", ct->mark)) |
141 | - return -ENOSPC; | |
148 | + goto release; | |
142 | 149 | #endif |
143 | 150 | |
144 | 151 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
145 | 152 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
146 | - return -ENOSPC; | |
153 | + goto release; | |
147 | 154 | #endif |
148 | 155 | |
149 | 156 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
150 | - return -ENOSPC; | |
151 | - | |
152 | - return 0; | |
157 | + goto release; | |
158 | + ret = 0; | |
159 | +release: | |
160 | + nf_ct_put(ct); | |
161 | + return ret; | |
153 | 162 | } |
154 | 163 | |
155 | 164 | static const struct seq_operations ct_seq_ops = { |
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
... | ... | @@ -262,6 +262,11 @@ |
262 | 262 | |
263 | 263 | return 0; |
264 | 264 | } |
265 | + | |
266 | +static int icmp_nlattr_tuple_size(void) | |
267 | +{ | |
268 | + return nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1); | |
269 | +} | |
265 | 270 | #endif |
266 | 271 | |
267 | 272 | #ifdef CONFIG_SYSCTL |
... | ... | @@ -309,6 +314,7 @@ |
309 | 314 | .me = NULL, |
310 | 315 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
311 | 316 | .tuple_to_nlattr = icmp_tuple_to_nlattr, |
317 | + .nlattr_tuple_size = icmp_nlattr_tuple_size, | |
312 | 318 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
313 | 319 | .nla_policy = icmp_nla_policy, |
314 | 320 | #endif |
net/ipv4/netfilter/nf_nat_core.c
... | ... | @@ -679,7 +679,7 @@ |
679 | 679 | static int __net_init nf_nat_net_init(struct net *net) |
680 | 680 | { |
681 | 681 | net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, |
682 | - &net->ipv4.nat_vmalloced); | |
682 | + &net->ipv4.nat_vmalloced, 0); | |
683 | 683 | if (!net->ipv4.nat_bysource) |
684 | 684 | return -ENOMEM; |
685 | 685 | return 0; |
net/ipv6/netfilter/ip6_tables.c
... | ... | @@ -89,25 +89,6 @@ |
89 | 89 | (nexthdr == IPPROTO_DSTOPTS) ); |
90 | 90 | } |
91 | 91 | |
92 | -static unsigned long ifname_compare(const char *_a, const char *_b, | |
93 | - const unsigned char *_mask) | |
94 | -{ | |
95 | - const unsigned long *a = (const unsigned long *)_a; | |
96 | - const unsigned long *b = (const unsigned long *)_b; | |
97 | - const unsigned long *mask = (const unsigned long *)_mask; | |
98 | - unsigned long ret; | |
99 | - | |
100 | - ret = (a[0] ^ b[0]) & mask[0]; | |
101 | - if (IFNAMSIZ > sizeof(unsigned long)) | |
102 | - ret |= (a[1] ^ b[1]) & mask[1]; | |
103 | - if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
104 | - ret |= (a[2] ^ b[2]) & mask[2]; | |
105 | - if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
106 | - ret |= (a[3] ^ b[3]) & mask[3]; | |
107 | - BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
108 | - return ret; | |
109 | -} | |
110 | - | |
111 | 92 | /* Returns whether matches rule or not. */ |
112 | 93 | /* Performance critical - called for every packet */ |
113 | 94 | static inline bool |
... | ... | @@ -138,7 +119,7 @@ |
138 | 119 | return false; |
139 | 120 | } |
140 | 121 | |
141 | - ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); | |
122 | + ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); | |
142 | 123 | |
143 | 124 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { |
144 | 125 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
... | ... | @@ -147,7 +128,7 @@ |
147 | 128 | return false; |
148 | 129 | } |
149 | 130 | |
150 | - ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); | |
131 | + ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask); | |
151 | 132 | |
152 | 133 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { |
153 | 134 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
... | ... | @@ -536,7 +517,9 @@ |
536 | 517 | && unconditional(&e->ipv6)) || visited) { |
537 | 518 | unsigned int oldpos, size; |
538 | 519 | |
539 | - if (t->verdict < -NF_MAX_VERDICT - 1) { | |
520 | + if ((strcmp(t->target.u.user.name, | |
521 | + IP6T_STANDARD_TARGET) == 0) && | |
522 | + t->verdict < -NF_MAX_VERDICT - 1) { | |
540 | 523 | duprintf("mark_source_chains: bad " |
541 | 524 | "negative verdict (%i)\n", |
542 | 525 | t->verdict); |
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
... | ... | @@ -342,6 +342,11 @@ |
342 | 342 | |
343 | 343 | return 0; |
344 | 344 | } |
345 | + | |
346 | +static int ipv6_nlattr_tuple_size(void) | |
347 | +{ | |
348 | + return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1); | |
349 | +} | |
345 | 350 | #endif |
346 | 351 | |
347 | 352 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { |
... | ... | @@ -353,6 +358,7 @@ |
353 | 358 | .get_l4proto = ipv6_get_l4proto, |
354 | 359 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
355 | 360 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, |
361 | + .nlattr_tuple_size = ipv6_nlattr_tuple_size, | |
356 | 362 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
357 | 363 | .nla_policy = ipv6_nla_policy, |
358 | 364 | #endif |
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
... | ... | @@ -269,6 +269,11 @@ |
269 | 269 | |
270 | 270 | return 0; |
271 | 271 | } |
272 | + | |
273 | +static int icmpv6_nlattr_tuple_size(void) | |
274 | +{ | |
275 | + return nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); | |
276 | +} | |
272 | 277 | #endif |
273 | 278 | |
274 | 279 | #ifdef CONFIG_SYSCTL |
... | ... | @@ -300,6 +305,7 @@ |
300 | 305 | .error = icmpv6_error, |
301 | 306 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
302 | 307 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
308 | + .nlattr_tuple_size = icmpv6_nlattr_tuple_size, | |
303 | 309 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
304 | 310 | .nla_policy = icmpv6_nla_policy, |
305 | 311 | #endif |
net/netfilter/Kconfig
... | ... | @@ -374,7 +374,7 @@ |
374 | 374 | |
375 | 375 | config NETFILTER_XT_TARGET_LED |
376 | 376 | tristate '"LED" target support' |
377 | - depends on LEDS_CLASS | |
377 | + depends on LEDS_CLASS && LED_TRIGGERS | |
378 | 378 | depends on NETFILTER_ADVANCED |
379 | 379 | help |
380 | 380 | This option adds a `LED' target, which allows you to blink LEDs in |
net/netfilter/nf_conntrack_core.c
... | ... | @@ -29,6 +29,7 @@ |
29 | 29 | #include <linux/netdevice.h> |
30 | 30 | #include <linux/socket.h> |
31 | 31 | #include <linux/mm.h> |
32 | +#include <linux/rculist_nulls.h> | |
32 | 33 | |
33 | 34 | #include <net/netfilter/nf_conntrack.h> |
34 | 35 | #include <net/netfilter/nf_conntrack_l3proto.h> |
... | ... | @@ -163,8 +164,8 @@ |
163 | 164 | clean_from_lists(struct nf_conn *ct) |
164 | 165 | { |
165 | 166 | pr_debug("clean_from_lists(%p)\n", ct); |
166 | - hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | |
167 | - hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode); | |
167 | + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); | |
168 | + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); | |
168 | 169 | |
169 | 170 | /* Destroy all pending expectations */ |
170 | 171 | nf_ct_remove_expectations(ct); |
... | ... | @@ -204,8 +205,8 @@ |
204 | 205 | |
205 | 206 | /* We overload first tuple to link into unconfirmed list. */ |
206 | 207 | if (!nf_ct_is_confirmed(ct)) { |
207 | - BUG_ON(hlist_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode)); | |
208 | - hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | |
208 | + BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); | |
209 | + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); | |
209 | 210 | } |
210 | 211 | |
211 | 212 | NF_CT_STAT_INC(net, delete); |
212 | 213 | |
213 | 214 | |
... | ... | @@ -242,18 +243,26 @@ |
242 | 243 | nf_ct_put(ct); |
243 | 244 | } |
244 | 245 | |
246 | +/* | |
247 | + * Warning : | |
248 | + * - Caller must take a reference on returned object | |
249 | + * and recheck nf_ct_tuple_equal(tuple, &h->tuple) | |
250 | + * OR | |
251 | + * - Caller must lock nf_conntrack_lock before calling this function | |
252 | + */ | |
245 | 253 | struct nf_conntrack_tuple_hash * |
246 | 254 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) |
247 | 255 | { |
248 | 256 | struct nf_conntrack_tuple_hash *h; |
249 | - struct hlist_node *n; | |
257 | + struct hlist_nulls_node *n; | |
250 | 258 | unsigned int hash = hash_conntrack(tuple); |
251 | 259 | |
252 | 260 | /* Disable BHs the entire time since we normally need to disable them |
253 | 261 | * at least once for the stats anyway. |
254 | 262 | */ |
255 | 263 | local_bh_disable(); |
256 | - hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | |
264 | +begin: | |
265 | + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { | |
257 | 266 | if (nf_ct_tuple_equal(tuple, &h->tuple)) { |
258 | 267 | NF_CT_STAT_INC(net, found); |
259 | 268 | local_bh_enable(); |
... | ... | @@ -261,6 +270,13 @@ |
261 | 270 | } |
262 | 271 | NF_CT_STAT_INC(net, searched); |
263 | 272 | } |
273 | + /* | |
274 | + * if the nulls value we got at the end of this lookup is | |
275 | + * not the expected one, we must restart lookup. | |
276 | + * We probably met an item that was moved to another chain. | |
277 | + */ | |
278 | + if (get_nulls_value(n) != hash) | |
279 | + goto begin; | |
264 | 280 | local_bh_enable(); |
265 | 281 | |
266 | 282 | return NULL; |
267 | 283 | |
... | ... | @@ -275,11 +291,18 @@ |
275 | 291 | struct nf_conn *ct; |
276 | 292 | |
277 | 293 | rcu_read_lock(); |
294 | +begin: | |
278 | 295 | h = __nf_conntrack_find(net, tuple); |
279 | 296 | if (h) { |
280 | 297 | ct = nf_ct_tuplehash_to_ctrack(h); |
281 | 298 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) |
282 | 299 | h = NULL; |
300 | + else { | |
301 | + if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { | |
302 | + nf_ct_put(ct); | |
303 | + goto begin; | |
304 | + } | |
305 | + } | |
283 | 306 | } |
284 | 307 | rcu_read_unlock(); |
285 | 308 | |
286 | 309 | |
... | ... | @@ -293,9 +316,9 @@ |
293 | 316 | { |
294 | 317 | struct net *net = nf_ct_net(ct); |
295 | 318 | |
296 | - hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | |
319 | + hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, | |
297 | 320 | &net->ct.hash[hash]); |
298 | - hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode, | |
321 | + hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, | |
299 | 322 | &net->ct.hash[repl_hash]); |
300 | 323 | } |
301 | 324 | |
... | ... | @@ -318,7 +341,7 @@ |
318 | 341 | struct nf_conntrack_tuple_hash *h; |
319 | 342 | struct nf_conn *ct; |
320 | 343 | struct nf_conn_help *help; |
321 | - struct hlist_node *n; | |
344 | + struct hlist_nulls_node *n; | |
322 | 345 | enum ip_conntrack_info ctinfo; |
323 | 346 | struct net *net; |
324 | 347 | |
325 | 348 | |
326 | 349 | |
... | ... | @@ -350,17 +373,17 @@ |
350 | 373 | /* See if there's one in the list already, including reverse: |
351 | 374 | NAT could have grabbed it without realizing, since we're |
352 | 375 | not in the hash. If there is, we lost race. */ |
353 | - hlist_for_each_entry(h, n, &net->ct.hash[hash], hnode) | |
376 | + hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) | |
354 | 377 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
355 | 378 | &h->tuple)) |
356 | 379 | goto out; |
357 | - hlist_for_each_entry(h, n, &net->ct.hash[repl_hash], hnode) | |
380 | + hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) | |
358 | 381 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
359 | 382 | &h->tuple)) |
360 | 383 | goto out; |
361 | 384 | |
362 | 385 | /* Remove from unconfirmed list */ |
363 | - hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | |
386 | + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); | |
364 | 387 | |
365 | 388 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
366 | 389 | /* Timer relative to confirmation time, not original |
367 | 390 | |
... | ... | @@ -399,14 +422,14 @@ |
399 | 422 | { |
400 | 423 | struct net *net = nf_ct_net(ignored_conntrack); |
401 | 424 | struct nf_conntrack_tuple_hash *h; |
402 | - struct hlist_node *n; | |
425 | + struct hlist_nulls_node *n; | |
403 | 426 | unsigned int hash = hash_conntrack(tuple); |
404 | 427 | |
405 | 428 | /* Disable BHs the entire time since we need to disable them at |
406 | 429 | * least once for the stats anyway. |
407 | 430 | */ |
408 | 431 | rcu_read_lock_bh(); |
409 | - hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | |
432 | + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { | |
410 | 433 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && |
411 | 434 | nf_ct_tuple_equal(tuple, &h->tuple)) { |
412 | 435 | NF_CT_STAT_INC(net, found); |
413 | 436 | |
... | ... | @@ -430,14 +453,14 @@ |
430 | 453 | /* Use oldest entry, which is roughly LRU */ |
431 | 454 | struct nf_conntrack_tuple_hash *h; |
432 | 455 | struct nf_conn *ct = NULL, *tmp; |
433 | - struct hlist_node *n; | |
456 | + struct hlist_nulls_node *n; | |
434 | 457 | unsigned int i, cnt = 0; |
435 | 458 | int dropped = 0; |
436 | 459 | |
437 | 460 | rcu_read_lock(); |
438 | 461 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
439 | - hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], | |
440 | - hnode) { | |
462 | + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], | |
463 | + hnnode) { | |
441 | 464 | tmp = nf_ct_tuplehash_to_ctrack(h); |
442 | 465 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) |
443 | 466 | ct = tmp; |
444 | 467 | |
445 | 468 | |
... | ... | @@ -508,27 +531,19 @@ |
508 | 531 | #ifdef CONFIG_NET_NS |
509 | 532 | ct->ct_net = net; |
510 | 533 | #endif |
511 | - INIT_RCU_HEAD(&ct->rcu); | |
512 | 534 | |
513 | 535 | return ct; |
514 | 536 | } |
515 | 537 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); |
516 | 538 | |
517 | -static void nf_conntrack_free_rcu(struct rcu_head *head) | |
518 | -{ | |
519 | - struct nf_conn *ct = container_of(head, struct nf_conn, rcu); | |
520 | - | |
521 | - nf_ct_ext_free(ct); | |
522 | - kmem_cache_free(nf_conntrack_cachep, ct); | |
523 | -} | |
524 | - | |
525 | 539 | void nf_conntrack_free(struct nf_conn *ct) |
526 | 540 | { |
527 | 541 | struct net *net = nf_ct_net(ct); |
528 | 542 | |
529 | 543 | nf_ct_ext_destroy(ct); |
530 | 544 | atomic_dec(&net->ct.count); |
531 | - call_rcu(&ct->rcu, nf_conntrack_free_rcu); | |
545 | + nf_ct_ext_free(ct); | |
546 | + kmem_cache_free(nf_conntrack_cachep, ct); | |
532 | 547 | } |
533 | 548 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
534 | 549 | |
... | ... | @@ -594,7 +609,7 @@ |
594 | 609 | } |
595 | 610 | |
596 | 611 | /* Overload tuple linked list to put us in unconfirmed list. */ |
597 | - hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | |
612 | + hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, | |
598 | 613 | &net->ct.unconfirmed); |
599 | 614 | |
600 | 615 | spin_unlock_bh(&nf_conntrack_lock); |
... | ... | @@ -906,6 +921,12 @@ |
906 | 921 | return 0; |
907 | 922 | } |
908 | 923 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); |
924 | + | |
925 | +int nf_ct_port_nlattr_tuple_size(void) | |
926 | +{ | |
927 | + return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | |
928 | +} | |
929 | +EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_tuple_size); | |
909 | 930 | #endif |
910 | 931 | |
911 | 932 | /* Used by ipt_REJECT and ip6t_REJECT. */ |
912 | 933 | |
913 | 934 | |
... | ... | @@ -934,17 +955,17 @@ |
934 | 955 | { |
935 | 956 | struct nf_conntrack_tuple_hash *h; |
936 | 957 | struct nf_conn *ct; |
937 | - struct hlist_node *n; | |
958 | + struct hlist_nulls_node *n; | |
938 | 959 | |
939 | 960 | spin_lock_bh(&nf_conntrack_lock); |
940 | 961 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { |
941 | - hlist_for_each_entry(h, n, &net->ct.hash[*bucket], hnode) { | |
962 | + hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { | |
942 | 963 | ct = nf_ct_tuplehash_to_ctrack(h); |
943 | 964 | if (iter(ct, data)) |
944 | 965 | goto found; |
945 | 966 | } |
946 | 967 | } |
947 | - hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) { | |
968 | + hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) { | |
948 | 969 | ct = nf_ct_tuplehash_to_ctrack(h); |
949 | 970 | if (iter(ct, data)) |
950 | 971 | set_bit(IPS_DYING_BIT, &ct->status); |
... | ... | @@ -992,7 +1013,7 @@ |
992 | 1013 | return 1; |
993 | 1014 | } |
994 | 1015 | |
995 | -void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int size) | |
1016 | +void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) | |
996 | 1017 | { |
997 | 1018 | if (vmalloced) |
998 | 1019 | vfree(hash); |
999 | 1020 | |
1000 | 1021 | |
1001 | 1022 | |
1002 | 1023 | |
... | ... | @@ -1060,26 +1081,28 @@ |
1060 | 1081 | } |
1061 | 1082 | } |
1062 | 1083 | |
1063 | -struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) | |
1084 | +void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls) | |
1064 | 1085 | { |
1065 | - struct hlist_head *hash; | |
1066 | - unsigned int size, i; | |
1086 | + struct hlist_nulls_head *hash; | |
1087 | + unsigned int nr_slots, i; | |
1088 | + size_t sz; | |
1067 | 1089 | |
1068 | 1090 | *vmalloced = 0; |
1069 | 1091 | |
1070 | - size = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_head)); | |
1071 | - hash = (void*)__get_free_pages(GFP_KERNEL|__GFP_NOWARN, | |
1072 | - get_order(sizeof(struct hlist_head) | |
1073 | - * size)); | |
1092 | + BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); | |
1093 | + nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); | |
1094 | + sz = nr_slots * sizeof(struct hlist_nulls_head); | |
1095 | + hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, | |
1096 | + get_order(sz)); | |
1074 | 1097 | if (!hash) { |
1075 | 1098 | *vmalloced = 1; |
1076 | 1099 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); |
1077 | - hash = vmalloc(sizeof(struct hlist_head) * size); | |
1100 | + hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); | |
1078 | 1101 | } |
1079 | 1102 | |
1080 | - if (hash) | |
1081 | - for (i = 0; i < size; i++) | |
1082 | - INIT_HLIST_HEAD(&hash[i]); | |
1103 | + if (hash && nulls) | |
1104 | + for (i = 0; i < nr_slots; i++) | |
1105 | + INIT_HLIST_NULLS_HEAD(&hash[i], i); | |
1083 | 1106 | |
1084 | 1107 | return hash; |
1085 | 1108 | } |
... | ... | @@ -1090,7 +1113,7 @@ |
1090 | 1113 | int i, bucket, vmalloced, old_vmalloced; |
1091 | 1114 | unsigned int hashsize, old_size; |
1092 | 1115 | int rnd; |
1093 | - struct hlist_head *hash, *old_hash; | |
1116 | + struct hlist_nulls_head *hash, *old_hash; | |
1094 | 1117 | struct nf_conntrack_tuple_hash *h; |
1095 | 1118 | |
1096 | 1119 | /* On boot, we can set this without any fancy locking. */ |
... | ... | @@ -1101,7 +1124,7 @@ |
1101 | 1124 | if (!hashsize) |
1102 | 1125 | return -EINVAL; |
1103 | 1126 | |
1104 | - hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced); | |
1127 | + hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced, 1); | |
1105 | 1128 | if (!hash) |
1106 | 1129 | return -ENOMEM; |
1107 | 1130 | |
1108 | 1131 | |
... | ... | @@ -1116,12 +1139,12 @@ |
1116 | 1139 | */ |
1117 | 1140 | spin_lock_bh(&nf_conntrack_lock); |
1118 | 1141 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
1119 | - while (!hlist_empty(&init_net.ct.hash[i])) { | |
1120 | - h = hlist_entry(init_net.ct.hash[i].first, | |
1121 | - struct nf_conntrack_tuple_hash, hnode); | |
1122 | - hlist_del_rcu(&h->hnode); | |
1142 | + while (!hlist_nulls_empty(&init_net.ct.hash[i])) { | |
1143 | + h = hlist_nulls_entry(init_net.ct.hash[i].first, | |
1144 | + struct nf_conntrack_tuple_hash, hnnode); | |
1145 | + hlist_nulls_del_rcu(&h->hnnode); | |
1123 | 1146 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); |
1124 | - hlist_add_head(&h->hnode, &hash[bucket]); | |
1147 | + hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); | |
1125 | 1148 | } |
1126 | 1149 | } |
1127 | 1150 | old_size = nf_conntrack_htable_size; |
... | ... | @@ -1172,7 +1195,7 @@ |
1172 | 1195 | |
1173 | 1196 | nf_conntrack_cachep = kmem_cache_create("nf_conntrack", |
1174 | 1197 | sizeof(struct nf_conn), |
1175 | - 0, 0, NULL); | |
1198 | + 0, SLAB_DESTROY_BY_RCU, NULL); | |
1176 | 1199 | if (!nf_conntrack_cachep) { |
1177 | 1200 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1178 | 1201 | ret = -ENOMEM; |
... | ... | @@ -1202,7 +1225,7 @@ |
1202 | 1225 | int ret; |
1203 | 1226 | |
1204 | 1227 | atomic_set(&net->ct.count, 0); |
1205 | - INIT_HLIST_HEAD(&net->ct.unconfirmed); | |
1228 | + INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); | |
1206 | 1229 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); |
1207 | 1230 | if (!net->ct.stat) { |
1208 | 1231 | ret = -ENOMEM; |
... | ... | @@ -1212,7 +1235,7 @@ |
1212 | 1235 | if (ret < 0) |
1213 | 1236 | goto err_ecache; |
1214 | 1237 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, |
1215 | - &net->ct.hash_vmalloc); | |
1238 | + &net->ct.hash_vmalloc, 1); | |
1216 | 1239 | if (!net->ct.hash) { |
1217 | 1240 | ret = -ENOMEM; |
1218 | 1241 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); |
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
... | ... | @@ -142,6 +142,7 @@ |
142 | 142 | |
143 | 143 | BUG_ON(me->expect_policy == NULL); |
144 | 144 | BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); |
145 | + BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1); | |
145 | 146 | |
146 | 147 | mutex_lock(&nf_ct_helper_mutex); |
147 | 148 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); |
... | ... | @@ -158,6 +159,7 @@ |
158 | 159 | struct nf_conntrack_tuple_hash *h; |
159 | 160 | struct nf_conntrack_expect *exp; |
160 | 161 | const struct hlist_node *n, *next; |
162 | + const struct hlist_nulls_node *nn; | |
161 | 163 | unsigned int i; |
162 | 164 | |
163 | 165 | /* Get rid of expectations */ |
164 | 166 | |
... | ... | @@ -174,10 +176,10 @@ |
174 | 176 | } |
175 | 177 | |
176 | 178 | /* Get rid of expecteds, set helpers to NULL. */ |
177 | - hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) | |
179 | + hlist_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode) | |
178 | 180 | unhelp(h, me); |
179 | 181 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
180 | - hlist_for_each_entry(h, n, &net->ct.hash[i], hnode) | |
182 | + hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) | |
181 | 183 | unhelp(h, me); |
182 | 184 | } |
183 | 185 | } |
... | ... | @@ -217,7 +219,7 @@ |
217 | 219 | |
218 | 220 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ |
219 | 221 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, |
220 | - &nf_ct_helper_vmalloc); | |
222 | + &nf_ct_helper_vmalloc, 0); | |
221 | 223 | if (!nf_ct_helper_hash) |
222 | 224 | return -ENOMEM; |
223 | 225 |
net/netfilter/nf_conntrack_netlink.c
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | #include <linux/module.h> |
20 | 20 | #include <linux/kernel.h> |
21 | 21 | #include <linux/rculist.h> |
22 | +#include <linux/rculist_nulls.h> | |
22 | 23 | #include <linux/types.h> |
23 | 24 | #include <linux/timer.h> |
24 | 25 | #include <linux/skbuff.h> |
... | ... | @@ -404,6 +405,78 @@ |
404 | 405 | } |
405 | 406 | |
406 | 407 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
408 | +/* | |
409 | + * The general structure of a ctnetlink event is | |
410 | + * | |
411 | + * CTA_TUPLE_ORIG | |
412 | + * <l3/l4-proto-attributes> | |
413 | + * CTA_TUPLE_REPLY | |
414 | + * <l3/l4-proto-attributes> | |
415 | + * CTA_ID | |
416 | + * ... | |
417 | + * CTA_PROTOINFO | |
418 | + * <l4-proto-attributes> | |
419 | + * CTA_TUPLE_MASTER | |
420 | + * <l3/l4-proto-attributes> | |
421 | + * | |
422 | + * Therefore the formular is | |
423 | + * | |
424 | + * size = sizeof(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas) | |
425 | + * + sizeof(protoinfo_nlas) | |
426 | + */ | |
427 | +static struct sk_buff * | |
428 | +ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) | |
429 | +{ | |
430 | + struct nf_conntrack_l3proto *l3proto; | |
431 | + struct nf_conntrack_l4proto *l4proto; | |
432 | + int len; | |
433 | + | |
434 | +#define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) | |
435 | + | |
436 | + /* proto independant part */ | |
437 | + len = NLMSG_SPACE(sizeof(struct nfgenmsg)) | |
438 | + + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ | |
439 | + + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ | |
440 | + + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ | |
441 | + + 3 * NLA_TYPE_SIZE(u_int8_t) /* CTA_PROTO_NUM */ | |
442 | + + NLA_TYPE_SIZE(u_int32_t) /* CTA_ID */ | |
443 | + + NLA_TYPE_SIZE(u_int32_t) /* CTA_STATUS */ | |
444 | +#ifdef CONFIG_NF_CT_ACCT | |
445 | + + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ | |
446 | + + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_PACKETS */ | |
447 | + + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_BYTES */ | |
448 | +#endif | |
449 | + + NLA_TYPE_SIZE(u_int32_t) /* CTA_TIMEOUT */ | |
450 | + + nla_total_size(0) /* CTA_PROTOINFO */ | |
451 | + + nla_total_size(0) /* CTA_HELP */ | |
452 | + + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ | |
453 | +#ifdef CONFIG_NF_CONNTRACK_SECMARK | |
454 | + + NLA_TYPE_SIZE(u_int32_t) /* CTA_SECMARK */ | |
455 | +#endif | |
456 | +#ifdef CONFIG_NF_NAT_NEEDED | |
457 | + + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ | |
458 | + + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_POS */ | |
459 | + + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_BEFORE */ | |
460 | + + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_AFTER */ | |
461 | +#endif | |
462 | +#ifdef CONFIG_NF_CONNTRACK_MARK | |
463 | + + NLA_TYPE_SIZE(u_int32_t) /* CTA_MARK */ | |
464 | +#endif | |
465 | + ; | |
466 | + | |
467 | +#undef NLA_TYPE_SIZE | |
468 | + | |
469 | + rcu_read_lock(); | |
470 | + l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | |
471 | + len += l3proto->nla_size; | |
472 | + | |
473 | + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | |
474 | + len += l4proto->nla_size; | |
475 | + rcu_read_unlock(); | |
476 | + | |
477 | + return alloc_skb(len, gfp); | |
478 | +} | |
479 | + | |
407 | 480 | static int ctnetlink_conntrack_event(struct notifier_block *this, |
408 | 481 | unsigned long events, void *ptr) |
409 | 482 | { |
... | ... | @@ -437,7 +510,7 @@ |
437 | 510 | if (!item->report && !nfnetlink_has_listeners(group)) |
438 | 511 | return NOTIFY_DONE; |
439 | 512 | |
440 | - skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | |
513 | + skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC); | |
441 | 514 | if (!skb) |
442 | 515 | return NOTIFY_DONE; |
443 | 516 | |
... | ... | @@ -536,7 +609,7 @@ |
536 | 609 | { |
537 | 610 | struct nf_conn *ct, *last; |
538 | 611 | struct nf_conntrack_tuple_hash *h; |
539 | - struct hlist_node *n; | |
612 | + struct hlist_nulls_node *n; | |
540 | 613 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
541 | 614 | u_int8_t l3proto = nfmsg->nfgen_family; |
542 | 615 | |
543 | 616 | |
544 | 617 | |
545 | 618 | |
546 | 619 | |
... | ... | @@ -544,27 +617,27 @@ |
544 | 617 | last = (struct nf_conn *)cb->args[1]; |
545 | 618 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { |
546 | 619 | restart: |
547 | - hlist_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], | |
548 | - hnode) { | |
620 | + hlist_nulls_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], | |
621 | + hnnode) { | |
549 | 622 | if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
550 | 623 | continue; |
551 | 624 | ct = nf_ct_tuplehash_to_ctrack(h); |
625 | + if (!atomic_inc_not_zero(&ct->ct_general.use)) | |
626 | + continue; | |
552 | 627 | /* Dump entries of a given L3 protocol number. |
553 | 628 | * If it is not specified, ie. l3proto == 0, |
554 | 629 | * then dump everything. */ |
555 | 630 | if (l3proto && nf_ct_l3num(ct) != l3proto) |
556 | - continue; | |
631 | + goto releasect; | |
557 | 632 | if (cb->args[1]) { |
558 | 633 | if (ct != last) |
559 | - continue; | |
634 | + goto releasect; | |
560 | 635 | cb->args[1] = 0; |
561 | 636 | } |
562 | 637 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
563 | 638 | cb->nlh->nlmsg_seq, |
564 | 639 | IPCTNL_MSG_CT_NEW, |
565 | 640 | 1, ct) < 0) { |
566 | - if (!atomic_inc_not_zero(&ct->ct_general.use)) | |
567 | - continue; | |
568 | 641 | cb->args[1] = (unsigned long)ct; |
569 | 642 | goto out; |
570 | 643 | } |
... | ... | @@ -577,6 +650,8 @@ |
577 | 650 | if (acct) |
578 | 651 | memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); |
579 | 652 | } |
653 | +releasect: | |
654 | + nf_ct_put(ct); | |
580 | 655 | } |
581 | 656 | if (cb->args[1]) { |
582 | 657 | cb->args[1] = 0; |
583 | 658 | |
... | ... | @@ -1242,13 +1317,12 @@ |
1242 | 1317 | if (err < 0) |
1243 | 1318 | goto err2; |
1244 | 1319 | |
1245 | - master_h = __nf_conntrack_find(&init_net, &master); | |
1320 | + master_h = nf_conntrack_find_get(&init_net, &master); | |
1246 | 1321 | if (master_h == NULL) { |
1247 | 1322 | err = -ENOENT; |
1248 | 1323 | goto err2; |
1249 | 1324 | } |
1250 | 1325 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); |
1251 | - nf_conntrack_get(&master_ct->ct_general); | |
1252 | 1326 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
1253 | 1327 | ct->master = master_ct; |
1254 | 1328 | } |
net/netfilter/nf_conntrack_proto.c
... | ... | @@ -167,6 +167,9 @@ |
167 | 167 | if (proto->l3proto >= AF_MAX) |
168 | 168 | return -EBUSY; |
169 | 169 | |
170 | + if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) | |
171 | + return -EINVAL; | |
172 | + | |
170 | 173 | mutex_lock(&nf_ct_proto_mutex); |
171 | 174 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { |
172 | 175 | ret = -EBUSY; |
... | ... | @@ -177,6 +180,9 @@ |
177 | 180 | if (ret < 0) |
178 | 181 | goto out_unlock; |
179 | 182 | |
183 | + if (proto->nlattr_tuple_size) | |
184 | + proto->nla_size = 3 * proto->nlattr_tuple_size(); | |
185 | + | |
180 | 186 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); |
181 | 187 | |
182 | 188 | out_unlock: |
... | ... | @@ -263,6 +269,10 @@ |
263 | 269 | if (l4proto->l3proto >= PF_MAX) |
264 | 270 | return -EBUSY; |
265 | 271 | |
272 | + if ((l4proto->to_nlattr && !l4proto->nlattr_size) | |
273 | + || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) | |
274 | + return -EINVAL; | |
275 | + | |
266 | 276 | mutex_lock(&nf_ct_proto_mutex); |
267 | 277 | if (!nf_ct_protos[l4proto->l3proto]) { |
268 | 278 | /* l3proto may be loaded latter. */ |
... | ... | @@ -289,6 +299,12 @@ |
289 | 299 | ret = nf_ct_l4proto_register_sysctl(l4proto); |
290 | 300 | if (ret < 0) |
291 | 301 | goto out_unlock; |
302 | + | |
303 | + l4proto->nla_size = 0; | |
304 | + if (l4proto->nlattr_size) | |
305 | + l4proto->nla_size += l4proto->nlattr_size(); | |
306 | + if (l4proto->nlattr_tuple_size) | |
307 | + l4proto->nla_size += 3 * l4proto->nlattr_tuple_size(); | |
292 | 308 | |
293 | 309 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], |
294 | 310 | l4proto); |
net/netfilter/nf_conntrack_proto_dccp.c
... | ... | @@ -669,6 +669,12 @@ |
669 | 669 | write_unlock_bh(&dccp_lock); |
670 | 670 | return 0; |
671 | 671 | } |
672 | + | |
673 | +static int dccp_nlattr_size(void) | |
674 | +{ | |
675 | + return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ | |
676 | + + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); | |
677 | +} | |
672 | 678 | #endif |
673 | 679 | |
674 | 680 | #ifdef CONFIG_SYSCTL |
675 | 681 | |
... | ... | @@ -749,8 +755,10 @@ |
749 | 755 | .print_conntrack = dccp_print_conntrack, |
750 | 756 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
751 | 757 | .to_nlattr = dccp_to_nlattr, |
758 | + .nlattr_size = dccp_nlattr_size, | |
752 | 759 | .from_nlattr = nlattr_to_dccp, |
753 | 760 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
761 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
754 | 762 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
755 | 763 | .nla_policy = nf_ct_port_nla_policy, |
756 | 764 | #endif |
... | ... | @@ -771,6 +779,7 @@ |
771 | 779 | .to_nlattr = dccp_to_nlattr, |
772 | 780 | .from_nlattr = nlattr_to_dccp, |
773 | 781 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
782 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
774 | 783 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
775 | 784 | .nla_policy = nf_ct_port_nla_policy, |
776 | 785 | #endif |
net/netfilter/nf_conntrack_proto_gre.c
... | ... | @@ -293,6 +293,7 @@ |
293 | 293 | .me = THIS_MODULE, |
294 | 294 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
295 | 295 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
296 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
296 | 297 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
297 | 298 | .nla_policy = nf_ct_port_nla_policy, |
298 | 299 | #endif |
net/netfilter/nf_conntrack_proto_sctp.c
... | ... | @@ -537,6 +537,12 @@ |
537 | 537 | |
538 | 538 | return 0; |
539 | 539 | } |
540 | + | |
541 | +static int sctp_nlattr_size(void) | |
542 | +{ | |
543 | + return nla_total_size(0) /* CTA_PROTOINFO_SCTP */ | |
544 | + + nla_policy_len(sctp_nla_policy, CTA_PROTOINFO_SCTP_MAX + 1); | |
545 | +} | |
540 | 546 | #endif |
541 | 547 | |
542 | 548 | #ifdef CONFIG_SYSCTL |
543 | 549 | |
... | ... | @@ -668,8 +674,10 @@ |
668 | 674 | .me = THIS_MODULE, |
669 | 675 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
670 | 676 | .to_nlattr = sctp_to_nlattr, |
677 | + .nlattr_size = sctp_nlattr_size, | |
671 | 678 | .from_nlattr = nlattr_to_sctp, |
672 | 679 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
680 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
673 | 681 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
674 | 682 | .nla_policy = nf_ct_port_nla_policy, |
675 | 683 | #endif |
676 | 684 | |
... | ... | @@ -696,8 +704,10 @@ |
696 | 704 | .me = THIS_MODULE, |
697 | 705 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
698 | 706 | .to_nlattr = sctp_to_nlattr, |
707 | + .nlattr_size = sctp_nlattr_size, | |
699 | 708 | .from_nlattr = nlattr_to_sctp, |
700 | 709 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
710 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
701 | 711 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
702 | 712 | .nla_policy = nf_ct_port_nla_policy, |
703 | 713 | #endif |
net/netfilter/nf_conntrack_proto_tcp.c
... | ... | @@ -1184,6 +1184,17 @@ |
1184 | 1184 | |
1185 | 1185 | return 0; |
1186 | 1186 | } |
1187 | + | |
1188 | +static int tcp_nlattr_size(void) | |
1189 | +{ | |
1190 | + return nla_total_size(0) /* CTA_PROTOINFO_TCP */ | |
1191 | + + nla_policy_len(tcp_nla_policy, CTA_PROTOINFO_TCP_MAX + 1); | |
1192 | +} | |
1193 | + | |
1194 | +static int tcp_nlattr_tuple_size(void) | |
1195 | +{ | |
1196 | + return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | |
1197 | +} | |
1187 | 1198 | #endif |
1188 | 1199 | |
1189 | 1200 | #ifdef CONFIG_SYSCTL |
1190 | 1201 | |
... | ... | @@ -1399,9 +1410,11 @@ |
1399 | 1410 | .error = tcp_error, |
1400 | 1411 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1401 | 1412 | .to_nlattr = tcp_to_nlattr, |
1413 | + .nlattr_size = tcp_nlattr_size, | |
1402 | 1414 | .from_nlattr = nlattr_to_tcp, |
1403 | 1415 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1404 | 1416 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1417 | + .nlattr_tuple_size = tcp_nlattr_tuple_size, | |
1405 | 1418 | .nla_policy = nf_ct_port_nla_policy, |
1406 | 1419 | #endif |
1407 | 1420 | #ifdef CONFIG_SYSCTL |
1408 | 1421 | |
... | ... | @@ -1429,9 +1442,11 @@ |
1429 | 1442 | .error = tcp_error, |
1430 | 1443 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1431 | 1444 | .to_nlattr = tcp_to_nlattr, |
1445 | + .nlattr_size = tcp_nlattr_size, | |
1432 | 1446 | .from_nlattr = nlattr_to_tcp, |
1433 | 1447 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1434 | 1448 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1449 | + .nlattr_tuple_size = tcp_nlattr_tuple_size, | |
1435 | 1450 | .nla_policy = nf_ct_port_nla_policy, |
1436 | 1451 | #endif |
1437 | 1452 | #ifdef CONFIG_SYSCTL |
net/netfilter/nf_conntrack_proto_udp.c
... | ... | @@ -195,6 +195,7 @@ |
195 | 195 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
196 | 196 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
197 | 197 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
198 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
198 | 199 | .nla_policy = nf_ct_port_nla_policy, |
199 | 200 | #endif |
200 | 201 | #ifdef CONFIG_SYSCTL |
... | ... | @@ -222,6 +223,7 @@ |
222 | 223 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
223 | 224 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
224 | 225 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
226 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
225 | 227 | .nla_policy = nf_ct_port_nla_policy, |
226 | 228 | #endif |
227 | 229 | #ifdef CONFIG_SYSCTL |
net/netfilter/nf_conntrack_proto_udplite.c
... | ... | @@ -180,6 +180,7 @@ |
180 | 180 | .error = udplite_error, |
181 | 181 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
182 | 182 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
183 | + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | |
183 | 184 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
184 | 185 | .nla_policy = nf_ct_port_nla_policy, |
185 | 186 | #endif |
net/netfilter/nf_conntrack_standalone.c
... | ... | @@ -44,40 +44,42 @@ |
44 | 44 | unsigned int bucket; |
45 | 45 | }; |
46 | 46 | |
47 | -static struct hlist_node *ct_get_first(struct seq_file *seq) | |
47 | +static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) | |
48 | 48 | { |
49 | 49 | struct net *net = seq_file_net(seq); |
50 | 50 | struct ct_iter_state *st = seq->private; |
51 | - struct hlist_node *n; | |
51 | + struct hlist_nulls_node *n; | |
52 | 52 | |
53 | 53 | for (st->bucket = 0; |
54 | 54 | st->bucket < nf_conntrack_htable_size; |
55 | 55 | st->bucket++) { |
56 | 56 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
57 | - if (n) | |
57 | + if (!is_a_nulls(n)) | |
58 | 58 | return n; |
59 | 59 | } |
60 | 60 | return NULL; |
61 | 61 | } |
62 | 62 | |
63 | -static struct hlist_node *ct_get_next(struct seq_file *seq, | |
64 | - struct hlist_node *head) | |
63 | +static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, | |
64 | + struct hlist_nulls_node *head) | |
65 | 65 | { |
66 | 66 | struct net *net = seq_file_net(seq); |
67 | 67 | struct ct_iter_state *st = seq->private; |
68 | 68 | |
69 | 69 | head = rcu_dereference(head->next); |
70 | - while (head == NULL) { | |
71 | - if (++st->bucket >= nf_conntrack_htable_size) | |
72 | - return NULL; | |
70 | + while (is_a_nulls(head)) { | |
71 | + if (likely(get_nulls_value(head) == st->bucket)) { | |
72 | + if (++st->bucket >= nf_conntrack_htable_size) | |
73 | + return NULL; | |
74 | + } | |
73 | 75 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
74 | 76 | } |
75 | 77 | return head; |
76 | 78 | } |
77 | 79 | |
78 | -static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | |
80 | +static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) | |
79 | 81 | { |
80 | - struct hlist_node *head = ct_get_first(seq); | |
82 | + struct hlist_nulls_node *head = ct_get_first(seq); | |
81 | 83 | |
82 | 84 | if (head) |
83 | 85 | while (pos && (head = ct_get_next(seq, head))) |
84 | 86 | |
85 | 87 | |
86 | 88 | |
87 | 89 | |
88 | 90 | |
89 | 91 | |
90 | 92 | |
91 | 93 | |
92 | 94 | |
93 | 95 | |
94 | 96 | |
95 | 97 | |
96 | 98 | |
97 | 99 | |
98 | 100 | |
99 | 101 | |
... | ... | @@ -107,67 +109,74 @@ |
107 | 109 | /* return 0 on success, 1 in case of error */ |
108 | 110 | static int ct_seq_show(struct seq_file *s, void *v) |
109 | 111 | { |
110 | - const struct nf_conntrack_tuple_hash *hash = v; | |
111 | - const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | |
112 | + struct nf_conntrack_tuple_hash *hash = v; | |
113 | + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | |
112 | 114 | const struct nf_conntrack_l3proto *l3proto; |
113 | 115 | const struct nf_conntrack_l4proto *l4proto; |
116 | + int ret = 0; | |
114 | 117 | |
115 | 118 | NF_CT_ASSERT(ct); |
119 | + if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | |
120 | + return 0; | |
116 | 121 | |
117 | 122 | /* we only want to print DIR_ORIGINAL */ |
118 | 123 | if (NF_CT_DIRECTION(hash)) |
119 | - return 0; | |
124 | + goto release; | |
120 | 125 | |
121 | 126 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
122 | 127 | NF_CT_ASSERT(l3proto); |
123 | 128 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
124 | 129 | NF_CT_ASSERT(l4proto); |
125 | 130 | |
131 | + ret = -ENOSPC; | |
126 | 132 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", |
127 | 133 | l3proto->name, nf_ct_l3num(ct), |
128 | 134 | l4proto->name, nf_ct_protonum(ct), |
129 | 135 | timer_pending(&ct->timeout) |
130 | 136 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
131 | - return -ENOSPC; | |
137 | + goto release; | |
132 | 138 | |
133 | 139 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
134 | - return -ENOSPC; | |
140 | + goto release; | |
135 | 141 | |
136 | 142 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
137 | 143 | l3proto, l4proto)) |
138 | - return -ENOSPC; | |
144 | + goto release; | |
139 | 145 | |
140 | 146 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
141 | - return -ENOSPC; | |
147 | + goto release; | |
142 | 148 | |
143 | 149 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
144 | 150 | if (seq_printf(s, "[UNREPLIED] ")) |
145 | - return -ENOSPC; | |
151 | + goto release; | |
146 | 152 | |
147 | 153 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
148 | 154 | l3proto, l4proto)) |
149 | - return -ENOSPC; | |
155 | + goto release; | |
150 | 156 | |
151 | 157 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
152 | - return -ENOSPC; | |
158 | + goto release; | |
153 | 159 | |
154 | 160 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
155 | 161 | if (seq_printf(s, "[ASSURED] ")) |
156 | - return -ENOSPC; | |
162 | + goto release; | |
157 | 163 | |
158 | 164 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
159 | 165 | if (seq_printf(s, "mark=%u ", ct->mark)) |
160 | - return -ENOSPC; | |
166 | + goto release; | |
161 | 167 | #endif |
162 | 168 | |
163 | 169 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
164 | 170 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
165 | - return -ENOSPC; | |
171 | + goto release; | |
166 | 172 | #endif |
167 | 173 | |
168 | 174 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
169 | - return -ENOSPC; | |
175 | + goto release; | |
170 | 176 | |
177 | + ret = 0; | |
178 | +release: | |
179 | + nf_ct_put(ct); | |
171 | 180 | return 0; |
172 | 181 | } |
173 | 182 |
net/netfilter/xt_connlimit.c
... | ... | @@ -108,7 +108,7 @@ |
108 | 108 | const struct nf_conntrack_tuple_hash *found; |
109 | 109 | struct xt_connlimit_conn *conn; |
110 | 110 | struct xt_connlimit_conn *tmp; |
111 | - const struct nf_conn *found_ct; | |
111 | + struct nf_conn *found_ct; | |
112 | 112 | struct list_head *hash; |
113 | 113 | bool addit = true; |
114 | 114 | int matches = 0; |
... | ... | @@ -123,7 +123,7 @@ |
123 | 123 | |
124 | 124 | /* check the saved connections */ |
125 | 125 | list_for_each_entry_safe(conn, tmp, hash, list) { |
126 | - found = __nf_conntrack_find(&init_net, &conn->tuple); | |
126 | + found = nf_conntrack_find_get(&init_net, &conn->tuple); | |
127 | 127 | found_ct = NULL; |
128 | 128 | |
129 | 129 | if (found != NULL) |
... | ... | @@ -151,6 +151,7 @@ |
151 | 151 | * we do not care about connections which are |
152 | 152 | * closed already -> ditch it |
153 | 153 | */ |
154 | + nf_ct_put(found_ct); | |
154 | 155 | list_del(&conn->list); |
155 | 156 | kfree(conn); |
156 | 157 | continue; |
... | ... | @@ -160,6 +161,7 @@ |
160 | 161 | match->family)) |
161 | 162 | /* same source network -> be counted! */ |
162 | 163 | ++matches; |
164 | + nf_ct_put(found_ct); | |
163 | 165 | } |
164 | 166 | |
165 | 167 | rcu_read_unlock(); |
net/netfilter/xt_physdev.c
... | ... | @@ -20,24 +20,7 @@ |
20 | 20 | MODULE_ALIAS("ipt_physdev"); |
21 | 21 | MODULE_ALIAS("ip6t_physdev"); |
22 | 22 | |
23 | -static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | |
24 | -{ | |
25 | - const unsigned long *a = (const unsigned long *)_a; | |
26 | - const unsigned long *b = (const unsigned long *)_b; | |
27 | - const unsigned long *mask = (const unsigned long *)_mask; | |
28 | - unsigned long ret; | |
29 | 23 | |
30 | - ret = (a[0] ^ b[0]) & mask[0]; | |
31 | - if (IFNAMSIZ > sizeof(unsigned long)) | |
32 | - ret |= (a[1] ^ b[1]) & mask[1]; | |
33 | - if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
34 | - ret |= (a[2] ^ b[2]) & mask[2]; | |
35 | - if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
36 | - ret |= (a[3] ^ b[3]) & mask[3]; | |
37 | - BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
38 | - return ret; | |
39 | -} | |
40 | - | |
41 | 24 | static bool |
42 | 25 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
43 | 26 | { |
... | ... | @@ -85,7 +68,7 @@ |
85 | 68 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) |
86 | 69 | goto match_outdev; |
87 | 70 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; |
88 | - ret = ifname_compare(indev, info->physindev, info->in_mask); | |
71 | + ret = ifname_compare_aligned(indev, info->physindev, info->in_mask); | |
89 | 72 | |
90 | 73 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) |
91 | 74 | return false; |
... | ... | @@ -95,7 +78,7 @@ |
95 | 78 | return true; |
96 | 79 | outdev = nf_bridge->physoutdev ? |
97 | 80 | nf_bridge->physoutdev->name : nulldevname; |
98 | - ret = ifname_compare(outdev, info->physoutdev, info->out_mask); | |
81 | + ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); | |
99 | 82 | |
100 | 83 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); |
101 | 84 | } |