diff options
author | Florian Westphal <fw@strlen.de> | 2009-06-05 07:24:24 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2009-06-05 07:24:24 -0400 |
commit | 10662aa3083f869c645cc2abf5d66849001e2f5d (patch) | |
tree | 7b4e96f00c3c4d5ca922901266121236eb2bd56e | |
parent | 61f5abcab152cbee3a041f8b9bcfe7afc83409ca (diff) |
netfilter: xt_NFQUEUE: queue balancing support
Adds support for specifying a range of queues instead of a single queue
id. Flows will be distributed across the given range.
This is useful for multicore systems: Instead of having a single
application read packets from a queue, start multiple
instances on queues x, x+1, .. x+n. Each instance can process
flows independently.
Packets for the same connection are put into the same queue.
Signed-off-by: Holger Eitzenberger <heitzenberger@astaro.com>
Signed-off-by: Florian Westphal <fwestphal@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/linux/netfilter/xt_NFQUEUE.h | 5 | ||||
-rw-r--r-- | net/netfilter/xt_NFQUEUE.c | 93 |
2 files changed, 98 insertions, 0 deletions
diff --git a/include/linux/netfilter/xt_NFQUEUE.h b/include/linux/netfilter/xt_NFQUEUE.h index 982a89f78272..2584f4a777de 100644 --- a/include/linux/netfilter/xt_NFQUEUE.h +++ b/include/linux/netfilter/xt_NFQUEUE.h | |||
@@ -15,4 +15,9 @@ struct xt_NFQ_info { | |||
15 | __u16 queuenum; | 15 | __u16 queuenum; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct xt_NFQ_info_v1 { | ||
19 | __u16 queuenum; | ||
20 | __u16 queues_total; | ||
21 | }; | ||
22 | |||
18 | #endif /* _XT_NFQ_TARGET_H */ | 23 | #endif /* _XT_NFQ_TARGET_H */ |
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 6e0f84d4d058..498b45101df7 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c | |||
@@ -11,6 +11,10 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | 13 | ||
14 | #include <linux/ip.h> | ||
15 | #include <linux/ipv6.h> | ||
16 | #include <linux/jhash.h> | ||
17 | |||
14 | #include <linux/netfilter.h> | 18 | #include <linux/netfilter.h> |
15 | #include <linux/netfilter_arp.h> | 19 | #include <linux/netfilter_arp.h> |
16 | #include <linux/netfilter/x_tables.h> | 20 | #include <linux/netfilter/x_tables.h> |
@@ -23,6 +27,8 @@ MODULE_ALIAS("ipt_NFQUEUE"); | |||
23 | MODULE_ALIAS("ip6t_NFQUEUE"); | 27 | MODULE_ALIAS("ip6t_NFQUEUE"); |
24 | MODULE_ALIAS("arpt_NFQUEUE"); | 28 | MODULE_ALIAS("arpt_NFQUEUE"); |
25 | 29 | ||
30 | static u32 jhash_initval __read_mostly; | ||
31 | |||
26 | static unsigned int | 32 | static unsigned int |
27 | nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) | 33 | nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) |
28 | { | 34 | { |
@@ -31,6 +37,72 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) | |||
31 | return NF_QUEUE_NR(tinfo->queuenum); | 37 | return NF_QUEUE_NR(tinfo->queuenum); |
32 | } | 38 | } |
33 | 39 | ||
40 | static u32 hash_v4(const struct sk_buff *skb) | ||
41 | { | ||
42 | const struct iphdr *iph = ip_hdr(skb); | ||
43 | u32 ipaddr; | ||
44 | |||
45 | /* packets in either direction go into same queue */ | ||
46 | ipaddr = iph->saddr ^ iph->daddr; | ||
47 | |||
48 | return jhash_2words(ipaddr, iph->protocol, jhash_initval); | ||
49 | } | ||
50 | |||
51 | static unsigned int | ||
52 | nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par) | ||
53 | { | ||
54 | const struct xt_NFQ_info_v1 *info = par->targinfo; | ||
55 | u32 queue = info->queuenum; | ||
56 | |||
57 | if (info->queues_total > 1) | ||
58 | queue = hash_v4(skb) % info->queues_total + queue; | ||
59 | return NF_QUEUE_NR(queue); | ||
60 | } | ||
61 | |||
62 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | ||
63 | static u32 hash_v6(const struct sk_buff *skb) | ||
64 | { | ||
65 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
66 | u32 addr[4]; | ||
67 | |||
68 | addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0]; | ||
69 | addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1]; | ||
70 | addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2]; | ||
71 | addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3]; | ||
72 | |||
73 | return jhash2(addr, ARRAY_SIZE(addr), jhash_initval); | ||
74 | } | ||
75 | |||
76 | static unsigned int | ||
77 | nfqueue_tg6_v1(struct sk_buff *skb, const struct xt_target_param *par) | ||
78 | { | ||
79 | const struct xt_NFQ_info_v1 *info = par->targinfo; | ||
80 | u32 queue = info->queuenum; | ||
81 | |||
82 | if (info->queues_total > 1) | ||
83 | queue = hash_v6(skb) % info->queues_total + queue; | ||
84 | return NF_QUEUE_NR(queue); | ||
85 | } | ||
86 | #endif | ||
87 | |||
88 | static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) | ||
89 | { | ||
90 | const struct xt_NFQ_info_v1 *info = par->targinfo; | ||
91 | u32 maxid; | ||
92 | |||
93 | if (info->queues_total == 0) { | ||
94 | pr_err("NFQUEUE: number of total queues is 0\n"); | ||
95 | return false; | ||
96 | } | ||
97 | maxid = info->queues_total - 1 + info->queuenum; | ||
98 | if (maxid > 0xffff) { | ||
99 | pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", | ||
100 | info->queues_total, maxid); | ||
101 | return false; | ||
102 | } | ||
103 | return true; | ||
104 | } | ||
105 | |||
34 | static struct xt_target nfqueue_tg_reg[] __read_mostly = { | 106 | static struct xt_target nfqueue_tg_reg[] __read_mostly = { |
35 | { | 107 | { |
36 | .name = "NFQUEUE", | 108 | .name = "NFQUEUE", |
@@ -39,10 +111,31 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = { | |||
39 | .targetsize = sizeof(struct xt_NFQ_info), | 111 | .targetsize = sizeof(struct xt_NFQ_info), |
40 | .me = THIS_MODULE, | 112 | .me = THIS_MODULE, |
41 | }, | 113 | }, |
114 | { | ||
115 | .name = "NFQUEUE", | ||
116 | .revision = 1, | ||
117 | .family = NFPROTO_IPV4, | ||
118 | .checkentry = nfqueue_tg_v1_check, | ||
119 | .target = nfqueue_tg4_v1, | ||
120 | .targetsize = sizeof(struct xt_NFQ_info_v1), | ||
121 | .me = THIS_MODULE, | ||
122 | }, | ||
123 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | ||
124 | { | ||
125 | .name = "NFQUEUE", | ||
126 | .revision = 1, | ||
127 | .family = NFPROTO_IPV6, | ||
128 | .checkentry = nfqueue_tg_v1_check, | ||
129 | .target = nfqueue_tg6_v1, | ||
130 | .targetsize = sizeof(struct xt_NFQ_info_v1), | ||
131 | .me = THIS_MODULE, | ||
132 | }, | ||
133 | #endif | ||
42 | }; | 134 | }; |
43 | 135 | ||
44 | static int __init nfqueue_tg_init(void) | 136 | static int __init nfqueue_tg_init(void) |
45 | { | 137 | { |
138 | get_random_bytes(&jhash_initval, sizeof(jhash_initval)); | ||
46 | return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); | 139 | return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); |
47 | } | 140 | } |
48 | 141 | ||