diff options
author | David S. Miller <davem@davemloft.net> | 2013-04-07 12:22:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-07 12:22:06 -0400 |
commit | d16658206a3a9a1cbe2cc062bee9ea7e782293a5 (patch) | |
tree | e7374985d7ec3bcfa77616ca449debfefa6849d9 /net/ipv6 | |
parent | 19952cc4f8f572493293a8caed27c4be89c5fc9d (diff) | |
parent | b8dd6a223eb86d537c2c6d8d28916c1f0ba3ea3c (diff) |
Merge branch 'master' of git://1984.lsi.us.es/nf-next
Pablo Neira Ayuso says:
====================
The following patchset contains Netfilter and IPVS updates for
your net-next tree, most relevantly they are:
* Add net namespace support to NFLOG, ULOG and ebt_ulog and NFQUEUE.
The LOG and ebt_log target has been also adapted, but they still
depend on the syslog netnamespace that seems to be missing, from
Gao Feng.
* Don't lose indications of congestion in IPv6 fragmentation handling,
from Hannes Frederic Sowa.i
* IPVS conversion to use RCU, including some code consolidation patches
and optimizations, also some from Julian Anastasov.
* cpu fanout support for NFQUEUE, from Holger Eitzenberger.
* Better error reporting to userspace when dropping packets from
all our _*_[xfrm|route]_me_harder functions, from Patrick McHardy.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 7 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 22 |
3 files changed, 26 insertions, 6 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 341b54ade72c..8861b1ef420e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -284,6 +284,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
284 | const char *hookname, *chainname, *comment; | 284 | const char *hookname, *chainname, *comment; |
285 | const struct ip6t_entry *iter; | 285 | const struct ip6t_entry *iter; |
286 | unsigned int rulenum = 0; | 286 | unsigned int rulenum = 0; |
287 | struct net *net = dev_net(in ? in : out); | ||
287 | 288 | ||
288 | table_base = private->entries[smp_processor_id()]; | 289 | table_base = private->entries[smp_processor_id()]; |
289 | root = get_entry(table_base, private->hook_entry[hook]); | 290 | root = get_entry(table_base, private->hook_entry[hook]); |
@@ -296,7 +297,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
296 | &chainname, &comment, &rulenum) != 0) | 297 | &chainname, &comment, &rulenum) != 0) |
297 | break; | 298 | break; |
298 | 299 | ||
299 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | 300 | nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo, |
300 | "TRACE: %s:%s:%s:%u ", | 301 | "TRACE: %s:%s:%s:%u ", |
301 | tablename, chainname, comment, rulenum); | 302 | tablename, chainname, comment, rulenum); |
302 | } | 303 | } |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 24df3dde0076..b3807c5cb888 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -131,7 +131,8 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
131 | type + 128); | 131 | type + 128); |
132 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); | 132 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); |
133 | if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6)) | 133 | if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6)) |
134 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | 134 | nf_log_packet(nf_ct_net(ct), PF_INET6, 0, skb, NULL, |
135 | NULL, NULL, | ||
135 | "nf_ct_icmpv6: invalid new with type %d ", | 136 | "nf_ct_icmpv6: invalid new with type %d ", |
136 | type + 128); | 137 | type + 128); |
137 | return false; | 138 | return false; |
@@ -203,7 +204,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, | |||
203 | icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); | 204 | icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); |
204 | if (icmp6h == NULL) { | 205 | if (icmp6h == NULL) { |
205 | if (LOG_INVALID(net, IPPROTO_ICMPV6)) | 206 | if (LOG_INVALID(net, IPPROTO_ICMPV6)) |
206 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | 207 | nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL, |
207 | "nf_ct_icmpv6: short packet "); | 208 | "nf_ct_icmpv6: short packet "); |
208 | return -NF_ACCEPT; | 209 | return -NF_ACCEPT; |
209 | } | 210 | } |
@@ -211,7 +212,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, | |||
211 | if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && | 212 | if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && |
212 | nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { | 213 | nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { |
213 | if (LOG_INVALID(net, IPPROTO_ICMPV6)) | 214 | if (LOG_INVALID(net, IPPROTO_ICMPV6)) |
214 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | 215 | nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL, |
215 | "nf_ct_icmpv6: ICMPv6 checksum failed "); | 216 | "nf_ct_icmpv6: ICMPv6 checksum failed "); |
216 | return -NF_ACCEPT; | 217 | return -NF_ACCEPT; |
217 | } | 218 | } |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 6700069949dd..dffdc1a389c5 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <net/rawv6.h> | 41 | #include <net/rawv6.h> |
42 | #include <net/ndisc.h> | 42 | #include <net/ndisc.h> |
43 | #include <net/addrconf.h> | 43 | #include <net/addrconf.h> |
44 | #include <net/inet_ecn.h> | ||
44 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 45 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
45 | #include <linux/sysctl.h> | 46 | #include <linux/sysctl.h> |
46 | #include <linux/netfilter.h> | 47 | #include <linux/netfilter.h> |
@@ -138,6 +139,11 @@ static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net) | |||
138 | } | 139 | } |
139 | #endif | 140 | #endif |
140 | 141 | ||
142 | static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) | ||
143 | { | ||
144 | return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); | ||
145 | } | ||
146 | |||
141 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 147 | static unsigned int nf_hashfn(struct inet_frag_queue *q) |
142 | { | 148 | { |
143 | const struct frag_queue *nq; | 149 | const struct frag_queue *nq; |
@@ -166,7 +172,7 @@ static void nf_ct_frag6_expire(unsigned long data) | |||
166 | /* Creation primitives. */ | 172 | /* Creation primitives. */ |
167 | static inline struct frag_queue *fq_find(struct net *net, __be32 id, | 173 | static inline struct frag_queue *fq_find(struct net *net, __be32 id, |
168 | u32 user, struct in6_addr *src, | 174 | u32 user, struct in6_addr *src, |
169 | struct in6_addr *dst) | 175 | struct in6_addr *dst, u8 ecn) |
170 | { | 176 | { |
171 | struct inet_frag_queue *q; | 177 | struct inet_frag_queue *q; |
172 | struct ip6_create_arg arg; | 178 | struct ip6_create_arg arg; |
@@ -176,6 +182,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, | |||
176 | arg.user = user; | 182 | arg.user = user; |
177 | arg.src = src; | 183 | arg.src = src; |
178 | arg.dst = dst; | 184 | arg.dst = dst; |
185 | arg.ecn = ecn; | ||
179 | 186 | ||
180 | read_lock_bh(&nf_frags.lock); | 187 | read_lock_bh(&nf_frags.lock); |
181 | hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); | 188 | hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); |
@@ -196,6 +203,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
196 | struct sk_buff *prev, *next; | 203 | struct sk_buff *prev, *next; |
197 | unsigned int payload_len; | 204 | unsigned int payload_len; |
198 | int offset, end; | 205 | int offset, end; |
206 | u8 ecn; | ||
199 | 207 | ||
200 | if (fq->q.last_in & INET_FRAG_COMPLETE) { | 208 | if (fq->q.last_in & INET_FRAG_COMPLETE) { |
201 | pr_debug("Already completed\n"); | 209 | pr_debug("Already completed\n"); |
@@ -213,6 +221,8 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
213 | return -1; | 221 | return -1; |
214 | } | 222 | } |
215 | 223 | ||
224 | ecn = ip6_frag_ecn(ipv6_hdr(skb)); | ||
225 | |||
216 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | 226 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
217 | const unsigned char *nh = skb_network_header(skb); | 227 | const unsigned char *nh = skb_network_header(skb); |
218 | skb->csum = csum_sub(skb->csum, | 228 | skb->csum = csum_sub(skb->csum, |
@@ -317,6 +327,7 @@ found: | |||
317 | } | 327 | } |
318 | fq->q.stamp = skb->tstamp; | 328 | fq->q.stamp = skb->tstamp; |
319 | fq->q.meat += skb->len; | 329 | fq->q.meat += skb->len; |
330 | fq->ecn |= ecn; | ||
320 | if (payload_len > fq->q.max_size) | 331 | if (payload_len > fq->q.max_size) |
321 | fq->q.max_size = payload_len; | 332 | fq->q.max_size = payload_len; |
322 | add_frag_mem_limit(&fq->q, skb->truesize); | 333 | add_frag_mem_limit(&fq->q, skb->truesize); |
@@ -352,12 +363,17 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
352 | { | 363 | { |
353 | struct sk_buff *fp, *op, *head = fq->q.fragments; | 364 | struct sk_buff *fp, *op, *head = fq->q.fragments; |
354 | int payload_len; | 365 | int payload_len; |
366 | u8 ecn; | ||
355 | 367 | ||
356 | inet_frag_kill(&fq->q, &nf_frags); | 368 | inet_frag_kill(&fq->q, &nf_frags); |
357 | 369 | ||
358 | WARN_ON(head == NULL); | 370 | WARN_ON(head == NULL); |
359 | WARN_ON(NFCT_FRAG6_CB(head)->offset != 0); | 371 | WARN_ON(NFCT_FRAG6_CB(head)->offset != 0); |
360 | 372 | ||
373 | ecn = ip_frag_ecn_table[fq->ecn]; | ||
374 | if (unlikely(ecn == 0xff)) | ||
375 | goto out_fail; | ||
376 | |||
361 | /* Unfragmented part is taken from the first segment. */ | 377 | /* Unfragmented part is taken from the first segment. */ |
362 | payload_len = ((head->data - skb_network_header(head)) - | 378 | payload_len = ((head->data - skb_network_header(head)) - |
363 | sizeof(struct ipv6hdr) + fq->q.len - | 379 | sizeof(struct ipv6hdr) + fq->q.len - |
@@ -428,6 +444,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
428 | head->dev = dev; | 444 | head->dev = dev; |
429 | head->tstamp = fq->q.stamp; | 445 | head->tstamp = fq->q.stamp; |
430 | ipv6_hdr(head)->payload_len = htons(payload_len); | 446 | ipv6_hdr(head)->payload_len = htons(payload_len); |
447 | ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn); | ||
431 | IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size; | 448 | IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size; |
432 | 449 | ||
433 | /* Yes, and fold redundant checksum back. 8) */ | 450 | /* Yes, and fold redundant checksum back. 8) */ |
@@ -572,7 +589,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
572 | inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false); | 589 | inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false); |
573 | local_bh_enable(); | 590 | local_bh_enable(); |
574 | 591 | ||
575 | fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr); | 592 | fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, |
593 | ip6_frag_ecn(hdr)); | ||
576 | if (fq == NULL) { | 594 | if (fq == NULL) { |
577 | pr_debug("Can't find and can't create new queue\n"); | 595 | pr_debug("Can't find and can't create new queue\n"); |
578 | goto ret_orig; | 596 | goto ret_orig; |