aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-03-25 12:11:44 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-25 12:11:44 -0400
commitda134825348faf797dc57c768bffc454ab7af34b (patch)
treef2778e4b523d4dd2bd79f9b3c9b8e722b70c5e1c /net
parentf5a03cf461f225d03ec7bf18b10b74e6f620cb49 (diff)
parentdece40e848f6e022f960dc9de54be518928460c3 (diff)
Merge branch 'master' of git://1984.lsi.us.es/nf-next
Pablo Neira Ayuso says: ==================== The following patchset contains Netfilter/IPVS updates for your net-next tree, they are: * Better performance in nfnetlink_queue by avoiding copy from the packet to netlink message, from Eric Dumazet. * Remove unnecessary locking in the exit path of ebt_ulog, from Gao Feng. * Use new function ipv6_iface_scope_id in nf_ct_ipv6, from Hannes Frederic Sowa. * A couple of sparse fixes for IPVS, from Julian Anastasov. * Use xor hashing in nfnetlink_queue, as suggested by Eric Dumazet, from myself. * Allow to dump expectations per master conntrack via ctnetlink, from myself. * A couple of cleanups to use PTR_RET in module init path, from Silviu-Mihai Popescu. * Remove nf_conntrack module a bit faster if netns are in use, from Vladimir Davydov. * Use checksum_partial in ip6t_NPT, from YOSHIFUJI Hideaki. * Sparse fix for nf_conntrack, from Stephen Hemminger. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/ebt_ulog.c3
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
-rw-r--r--net/ipv4/netfilter/arptable_filter.c4
-rw-r--r--net/ipv6/netfilter/ip6t_NPT.c11
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_est.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c47
-rw-r--r--net/netfilter/nf_conntrack_netlink.c100
-rw-r--r--net/netfilter/nf_conntrack_standalone.c16
-rw-r--r--net/netfilter/nfnetlink_queue_core.c96
12 files changed, 226 insertions, 81 deletions
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 3bf43f7bb9d4..442b0321acb9 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -319,12 +319,11 @@ static void __exit ebt_ulog_fini(void)
319 for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { 319 for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
320 ub = &ulog_buffers[i]; 320 ub = &ulog_buffers[i];
321 del_timer(&ub->timer); 321 del_timer(&ub->timer);
322 spin_lock_bh(&ub->lock); 322
323 if (ub->skb) { 323 if (ub->skb) {
324 kfree_skb(ub->skb); 324 kfree_skb(ub->skb);
325 ub->skb = NULL; 325 ub->skb = NULL;
326 } 326 }
327 spin_unlock_bh(&ub->lock);
328 } 327 }
329 netlink_kernel_release(ebtulognl); 328 netlink_kernel_release(ebtulognl);
330} 329}
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 40d8258bf74f..70f656ce0f4a 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -64,9 +64,7 @@ static int ebt_broute(struct sk_buff *skb)
64static int __net_init broute_net_init(struct net *net) 64static int __net_init broute_net_init(struct net *net)
65{ 65{
66 net->xt.broute_table = ebt_register_table(net, &broute_table); 66 net->xt.broute_table = ebt_register_table(net, &broute_table);
67 if (IS_ERR(net->xt.broute_table)) 67 return PTR_RET(net->xt.broute_table);
68 return PTR_ERR(net->xt.broute_table);
69 return 0;
70} 68}
71 69
72static void __net_exit broute_net_exit(struct net *net) 70static void __net_exit broute_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 79ca5e70d497..eadab1ed6500 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -48,9 +48,7 @@ static int __net_init arptable_filter_net_init(struct net *net)
48 net->ipv4.arptable_filter = 48 net->ipv4.arptable_filter =
49 arpt_register_table(net, &packet_filter, repl); 49 arpt_register_table(net, &packet_filter, repl);
50 kfree(repl); 50 kfree(repl);
51 if (IS_ERR(net->ipv4.arptable_filter)) 51 return PTR_RET(net->ipv4.arptable_filter);
52 return PTR_ERR(net->ipv4.arptable_filter);
53 return 0;
54} 52}
55 53
56static void __net_exit arptable_filter_net_exit(struct net *net) 54static void __net_exit arptable_filter_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
index 33608c610276..938e0b7ea1bd 100644
--- a/net/ipv6/netfilter/ip6t_NPT.c
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -18,9 +18,8 @@
18static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) 18static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
19{ 19{
20 struct ip6t_npt_tginfo *npt = par->targinfo; 20 struct ip6t_npt_tginfo *npt = par->targinfo;
21 __wsum src_sum = 0, dst_sum = 0;
22 struct in6_addr pfx; 21 struct in6_addr pfx;
23 unsigned int i; 22 __wsum src_sum, dst_sum;
24 23
25 if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) 24 if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
26 return -EINVAL; 25 return -EINVAL;
@@ -33,12 +32,8 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
33 if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6)) 32 if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6))
34 return -EINVAL; 33 return -EINVAL;
35 34
36 for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { 35 src_sum = csum_partial(&npt->src_pfx.in6, sizeof(npt->src_pfx.in6), 0);
37 src_sum = csum_add(src_sum, 36 dst_sum = csum_partial(&npt->dst_pfx.in6, sizeof(npt->dst_pfx.in6), 0);
38 (__force __wsum)npt->src_pfx.in6.s6_addr16[i]);
39 dst_sum = csum_add(dst_sum,
40 (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]);
41 }
42 37
43 npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum)); 38 npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum));
44 return 0; 39 return 0;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 2b6c226f5198..97bcf2bae857 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -330,12 +330,8 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
330 sizeof(sin6.sin6_addr)); 330 sizeof(sin6.sin6_addr));
331 331
332 nf_ct_put(ct); 332 nf_ct_put(ct);
333 333 sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
334 if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) 334 sk->sk_bound_dev_if);
335 sin6.sin6_scope_id = sk->sk_bound_dev_if;
336 else
337 sin6.sin6_scope_id = 0;
338
339 return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 335 return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
340} 336}
341 337
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 61f49d241712..2aef23ed748b 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -69,10 +69,7 @@ EXPORT_SYMBOL(ip_vs_conn_put);
69EXPORT_SYMBOL(ip_vs_get_debug_level); 69EXPORT_SYMBOL(ip_vs_get_debug_level);
70#endif 70#endif
71 71
72int ip_vs_net_id __read_mostly; 72static int ip_vs_net_id __read_mostly;
73#ifdef IP_VS_GENERIC_NETNS
74EXPORT_SYMBOL(ip_vs_net_id);
75#endif
76/* netns cnt used for uniqueness */ 73/* netns cnt used for uniqueness */
77static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0); 74static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
78 75
@@ -1181,9 +1178,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1181 iph.len)))) { 1178 iph.len)))) {
1182#ifdef CONFIG_IP_VS_IPV6 1179#ifdef CONFIG_IP_VS_IPV6
1183 if (af == AF_INET6) { 1180 if (af == AF_INET6) {
1184 struct net *net =
1185 dev_net(skb_dst(skb)->dev);
1186
1187 if (!skb->dev) 1181 if (!skb->dev)
1188 skb->dev = net->loopback_dev; 1182 skb->dev = net->loopback_dev;
1189 icmpv6_send(skb, 1183 icmpv6_send(skb,
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 9e2d1cccd1eb..8104120f16a5 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -271,16 +271,18 @@ ip_vs_svc_hashkey(struct net *net, int af, unsigned int proto,
271{ 271{
272 register unsigned int porth = ntohs(port); 272 register unsigned int porth = ntohs(port);
273 __be32 addr_fold = addr->ip; 273 __be32 addr_fold = addr->ip;
274 __u32 ahash;
274 275
275#ifdef CONFIG_IP_VS_IPV6 276#ifdef CONFIG_IP_VS_IPV6
276 if (af == AF_INET6) 277 if (af == AF_INET6)
277 addr_fold = addr->ip6[0]^addr->ip6[1]^ 278 addr_fold = addr->ip6[0]^addr->ip6[1]^
278 addr->ip6[2]^addr->ip6[3]; 279 addr->ip6[2]^addr->ip6[3];
279#endif 280#endif
280 addr_fold ^= ((size_t)net>>8); 281 ahash = ntohl(addr_fold);
282 ahash ^= ((size_t) net >> 8);
281 283
282 return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth) 284 return (proto ^ ahash ^ (porth >> IP_VS_SVC_TAB_BITS) ^ porth) &
283 & IP_VS_SVC_TAB_MASK; 285 IP_VS_SVC_TAB_MASK;
284} 286}
285 287
286/* 288/*
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 0fac6017b6fb..6bee6d0c73a5 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -56,7 +56,7 @@
56 * Make a summary from each cpu 56 * Make a summary from each cpu
57 */ 57 */
58static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum, 58static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
59 struct ip_vs_cpu_stats *stats) 59 struct ip_vs_cpu_stats __percpu *stats)
60{ 60{
61 int i; 61 int i;
62 62
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index c8e001a9c45b..007e8c43d19a 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -48,6 +48,7 @@
48#include <net/netfilter/nf_conntrack_labels.h> 48#include <net/netfilter/nf_conntrack_labels.h>
49#include <net/netfilter/nf_nat.h> 49#include <net/netfilter/nf_nat.h>
50#include <net/netfilter/nf_nat_core.h> 50#include <net/netfilter/nf_nat_core.h>
51#include <net/netfilter/nf_nat_helper.h>
51 52
52#define NF_CONNTRACK_VERSION "0.5.0" 53#define NF_CONNTRACK_VERSION "0.5.0"
53 54
@@ -1364,30 +1365,48 @@ void nf_conntrack_cleanup_end(void)
1364 */ 1365 */
1365void nf_conntrack_cleanup_net(struct net *net) 1366void nf_conntrack_cleanup_net(struct net *net)
1366{ 1367{
1368 LIST_HEAD(single);
1369
1370 list_add(&net->exit_list, &single);
1371 nf_conntrack_cleanup_net_list(&single);
1372}
1373
1374void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
1375{
1376 int busy;
1377 struct net *net;
1378
1367 /* 1379 /*
1368 * This makes sure all current packets have passed through 1380 * This makes sure all current packets have passed through
1369 * netfilter framework. Roll on, two-stage module 1381 * netfilter framework. Roll on, two-stage module
1370 * delete... 1382 * delete...
1371 */ 1383 */
1372 synchronize_net(); 1384 synchronize_net();
1373 i_see_dead_people: 1385i_see_dead_people:
1374 nf_ct_iterate_cleanup(net, kill_all, NULL); 1386 busy = 0;
1375 nf_ct_release_dying_list(net); 1387 list_for_each_entry(net, net_exit_list, exit_list) {
1376 if (atomic_read(&net->ct.count) != 0) { 1388 nf_ct_iterate_cleanup(net, kill_all, NULL);
1389 nf_ct_release_dying_list(net);
1390 if (atomic_read(&net->ct.count) != 0)
1391 busy = 1;
1392 }
1393 if (busy) {
1377 schedule(); 1394 schedule();
1378 goto i_see_dead_people; 1395 goto i_see_dead_people;
1379 } 1396 }
1380 1397
1381 nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); 1398 list_for_each_entry(net, net_exit_list, exit_list) {
1382 nf_conntrack_proto_pernet_fini(net); 1399 nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
1383 nf_conntrack_helper_pernet_fini(net); 1400 nf_conntrack_proto_pernet_fini(net);
1384 nf_conntrack_ecache_pernet_fini(net); 1401 nf_conntrack_helper_pernet_fini(net);
1385 nf_conntrack_tstamp_pernet_fini(net); 1402 nf_conntrack_ecache_pernet_fini(net);
1386 nf_conntrack_acct_pernet_fini(net); 1403 nf_conntrack_tstamp_pernet_fini(net);
1387 nf_conntrack_expect_pernet_fini(net); 1404 nf_conntrack_acct_pernet_fini(net);
1388 kmem_cache_destroy(net->ct.nf_conntrack_cachep); 1405 nf_conntrack_expect_pernet_fini(net);
1389 kfree(net->ct.slabname); 1406 kmem_cache_destroy(net->ct.nf_conntrack_cachep);
1390 free_percpu(net->ct.stat); 1407 kfree(net->ct.slabname);
1408 free_percpu(net->ct.stat);
1409 }
1391} 1410}
1392 1411
1393void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) 1412void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 9904b15f600e..6d0f8a17c5b7 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2409,6 +2409,92 @@ out:
2409 return skb->len; 2409 return skb->len;
2410} 2410}
2411 2411
2412static int
2413ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
2414{
2415 struct nf_conntrack_expect *exp, *last;
2416 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2417 struct nf_conn *ct = cb->data;
2418 struct nf_conn_help *help = nfct_help(ct);
2419 u_int8_t l3proto = nfmsg->nfgen_family;
2420
2421 if (cb->args[0])
2422 return 0;
2423
2424 rcu_read_lock();
2425 last = (struct nf_conntrack_expect *)cb->args[1];
2426restart:
2427 hlist_for_each_entry(exp, &help->expectations, lnode) {
2428 if (l3proto && exp->tuple.src.l3num != l3proto)
2429 continue;
2430 if (cb->args[1]) {
2431 if (exp != last)
2432 continue;
2433 cb->args[1] = 0;
2434 }
2435 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).portid,
2436 cb->nlh->nlmsg_seq,
2437 IPCTNL_MSG_EXP_NEW,
2438 exp) < 0) {
2439 if (!atomic_inc_not_zero(&exp->use))
2440 continue;
2441 cb->args[1] = (unsigned long)exp;
2442 goto out;
2443 }
2444 }
2445 if (cb->args[1]) {
2446 cb->args[1] = 0;
2447 goto restart;
2448 }
2449 cb->args[0] = 1;
2450out:
2451 rcu_read_unlock();
2452 if (last)
2453 nf_ct_expect_put(last);
2454
2455 return skb->len;
2456}
2457
2458static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
2459 const struct nlmsghdr *nlh,
2460 const struct nlattr * const cda[])
2461{
2462 int err;
2463 struct net *net = sock_net(ctnl);
2464 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2465 u_int8_t u3 = nfmsg->nfgen_family;
2466 struct nf_conntrack_tuple tuple;
2467 struct nf_conntrack_tuple_hash *h;
2468 struct nf_conn *ct;
2469 u16 zone = 0;
2470 struct netlink_dump_control c = {
2471 .dump = ctnetlink_exp_ct_dump_table,
2472 .done = ctnetlink_exp_done,
2473 };
2474
2475 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
2476 if (err < 0)
2477 return err;
2478
2479 if (cda[CTA_EXPECT_ZONE]) {
2480 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2481 if (err < 0)
2482 return err;
2483 }
2484
2485 h = nf_conntrack_find_get(net, zone, &tuple);
2486 if (!h)
2487 return -ENOENT;
2488
2489 ct = nf_ct_tuplehash_to_ctrack(h);
2490 c.data = ct;
2491
2492 err = netlink_dump_start(ctnl, skb, nlh, &c);
2493 nf_ct_put(ct);
2494
2495 return err;
2496}
2497
2412static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { 2498static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
2413 [CTA_EXPECT_MASTER] = { .type = NLA_NESTED }, 2499 [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
2414 [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED }, 2500 [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
@@ -2439,11 +2525,15 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
2439 int err; 2525 int err;
2440 2526
2441 if (nlh->nlmsg_flags & NLM_F_DUMP) { 2527 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2442 struct netlink_dump_control c = { 2528 if (cda[CTA_EXPECT_MASTER])
2443 .dump = ctnetlink_exp_dump_table, 2529 return ctnetlink_dump_exp_ct(ctnl, skb, nlh, cda);
2444 .done = ctnetlink_exp_done, 2530 else {
2445 }; 2531 struct netlink_dump_control c = {
2446 return netlink_dump_start(ctnl, skb, nlh, &c); 2532 .dump = ctnetlink_exp_dump_table,
2533 .done = ctnetlink_exp_done,
2534 };
2535 return netlink_dump_start(ctnl, skb, nlh, &c);
2536 }
2447 } 2537 }
2448 2538
2449 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); 2539 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 6bcce401fd1c..6c69fbdb8361 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -545,16 +545,20 @@ out_init:
545 return ret; 545 return ret;
546} 546}
547 547
548static void nf_conntrack_pernet_exit(struct net *net) 548static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
549{ 549{
550 nf_conntrack_standalone_fini_sysctl(net); 550 struct net *net;
551 nf_conntrack_standalone_fini_proc(net); 551
552 nf_conntrack_cleanup_net(net); 552 list_for_each_entry(net, net_exit_list, exit_list) {
553 nf_conntrack_standalone_fini_sysctl(net);
554 nf_conntrack_standalone_fini_proc(net);
555 }
556 nf_conntrack_cleanup_net_list(net_exit_list);
553} 557}
554 558
555static struct pernet_operations nf_conntrack_net_ops = { 559static struct pernet_operations nf_conntrack_net_ops = {
556 .init = nf_conntrack_pernet_init, 560 .init = nf_conntrack_pernet_init,
557 .exit = nf_conntrack_pernet_exit, 561 .exit_batch = nf_conntrack_pernet_exit,
558}; 562};
559 563
560static int __init nf_conntrack_standalone_init(void) 564static int __init nf_conntrack_standalone_init(void)
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 1cb48540f86a..19845e34f70f 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -73,7 +73,7 @@ static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
73 73
74static inline u_int8_t instance_hashfn(u_int16_t queue_num) 74static inline u_int8_t instance_hashfn(u_int16_t queue_num)
75{ 75{
76 return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; 76 return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
77} 77}
78 78
79static struct nfqnl_instance * 79static struct nfqnl_instance *
@@ -217,14 +217,59 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
217 spin_unlock_bh(&queue->lock); 217 spin_unlock_bh(&queue->lock);
218} 218}
219 219
220static void
221nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
222{
223 int i, j = 0;
224 int plen = 0; /* length of skb->head fragment */
225 struct page *page;
226 unsigned int offset;
227
228 /* dont bother with small payloads */
229 if (len <= skb_tailroom(to)) {
230 skb_copy_bits(from, 0, skb_put(to, len), len);
231 return;
232 }
233
234 if (hlen) {
235 skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
236 len -= hlen;
237 } else {
238 plen = min_t(int, skb_headlen(from), len);
239 if (plen) {
240 page = virt_to_head_page(from->head);
241 offset = from->data - (unsigned char *)page_address(page);
242 __skb_fill_page_desc(to, 0, page, offset, plen);
243 get_page(page);
244 j = 1;
245 len -= plen;
246 }
247 }
248
249 to->truesize += len + plen;
250 to->len += len + plen;
251 to->data_len += len + plen;
252
253 for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
254 if (!len)
255 break;
256 skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
257 skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
258 len -= skb_shinfo(to)->frags[j].size;
259 skb_frag_ref(to, j);
260 j++;
261 }
262 skb_shinfo(to)->nr_frags = j;
263}
264
220static struct sk_buff * 265static struct sk_buff *
221nfqnl_build_packet_message(struct nfqnl_instance *queue, 266nfqnl_build_packet_message(struct nfqnl_instance *queue,
222 struct nf_queue_entry *entry, 267 struct nf_queue_entry *entry,
223 __be32 **packet_id_ptr) 268 __be32 **packet_id_ptr)
224{ 269{
225 sk_buff_data_t old_tail;
226 size_t size; 270 size_t size;
227 size_t data_len = 0, cap_len = 0; 271 size_t data_len = 0, cap_len = 0;
272 int hlen = 0;
228 struct sk_buff *skb; 273 struct sk_buff *skb;
229 struct nlattr *nla; 274 struct nlattr *nla;
230 struct nfqnl_msg_packet_hdr *pmsg; 275 struct nfqnl_msg_packet_hdr *pmsg;
@@ -246,8 +291,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
246#endif 291#endif
247 + nla_total_size(sizeof(u_int32_t)) /* mark */ 292 + nla_total_size(sizeof(u_int32_t)) /* mark */
248 + nla_total_size(sizeof(struct nfqnl_msg_packet_hw)) 293 + nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
249 + nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp) 294 + nla_total_size(sizeof(u_int32_t)); /* cap_len */
250 + nla_total_size(sizeof(u_int32_t))); /* cap_len */ 295
296 if (entskb->tstamp.tv64)
297 size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
251 298
252 outdev = entry->outdev; 299 outdev = entry->outdev;
253 300
@@ -265,7 +312,16 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
265 if (data_len == 0 || data_len > entskb->len) 312 if (data_len == 0 || data_len > entskb->len)
266 data_len = entskb->len; 313 data_len = entskb->len;
267 314
268 size += nla_total_size(data_len); 315
316 if (!entskb->head_frag ||
317 skb_headlen(entskb) < L1_CACHE_BYTES ||
318 skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS)
319 hlen = skb_headlen(entskb);
320
321 if (skb_has_frag_list(entskb))
322 hlen = entskb->len;
323 hlen = min_t(int, data_len, hlen);
324 size += sizeof(struct nlattr) + hlen;
269 cap_len = entskb->len; 325 cap_len = entskb->len;
270 break; 326 break;
271 } 327 }
@@ -277,7 +333,6 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
277 if (!skb) 333 if (!skb)
278 return NULL; 334 return NULL;
279 335
280 old_tail = skb->tail;
281 nlh = nlmsg_put(skb, 0, 0, 336 nlh = nlmsg_put(skb, 0, 0,
282 NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, 337 NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
283 sizeof(struct nfgenmsg), 0); 338 sizeof(struct nfgenmsg), 0);
@@ -382,31 +437,26 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
382 goto nla_put_failure; 437 goto nla_put_failure;
383 } 438 }
384 439
440 if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
441 goto nla_put_failure;
442
443 if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
444 goto nla_put_failure;
445
385 if (data_len) { 446 if (data_len) {
386 struct nlattr *nla; 447 struct nlattr *nla;
387 int sz = nla_attr_size(data_len);
388 448
389 if (skb_tailroom(skb) < nla_total_size(data_len)) { 449 if (skb_tailroom(skb) < sizeof(*nla) + hlen)
390 printk(KERN_WARNING "nf_queue: no tailroom!\n"); 450 goto nla_put_failure;
391 kfree_skb(skb);
392 return NULL;
393 }
394 451
395 nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len)); 452 nla = (struct nlattr *)skb_put(skb, sizeof(*nla));
396 nla->nla_type = NFQA_PAYLOAD; 453 nla->nla_type = NFQA_PAYLOAD;
397 nla->nla_len = sz; 454 nla->nla_len = nla_attr_size(data_len);
398 455
399 if (skb_copy_bits(entskb, 0, nla_data(nla), data_len)) 456 nfqnl_zcopy(skb, entskb, data_len, hlen);
400 BUG();
401 } 457 }
402 458
403 if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0) 459 nlh->nlmsg_len = skb->len;
404 goto nla_put_failure;
405
406 if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
407 goto nla_put_failure;
408
409 nlh->nlmsg_len = skb->tail - old_tail;
410 return skb; 460 return skb;
411 461
412nla_put_failure: 462nla_put_failure: