diff options
author | holger@eitzenberger.org <holger@eitzenberger.org> | 2013-03-23 06:04:03 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-01 19:25:44 -0400 |
commit | 8746ddcf12bb263ad240e095ef16531006caeb50 (patch) | |
tree | ca4f131f820d6cce4724f5471112624687f2bdd1 /net/netfilter | |
parent | f0165888610a1701a39670c7eadf63a61fad708d (diff) |
netfilter: xt_NFQUEUE: introduce CPU fanout
Current NFQUEUE target uses a hash, computed over source and
destination address (and other parameters), for steering the packet
to the actual NFQUEUE. This, however forgets about the fact that the
packet eventually is handled by a particular CPU on user request.
If E. g.
1) IRQ affinity is used to handle packets on a particular CPU already
(both single-queue or multi-queue case)
and/or
2) RPS is used to steer packets to a specific softirq
the target easily chooses an NFQUEUE which is not handled by a process
pinned to the same CPU.
The idea is therefore to use the CPU index for determining the
NFQUEUE handling the packet.
E. g. when having a system with 4 CPUs, 4 MQ queues and 4 NFQUEUEs it
looks like this:
+-----+ +-----+ +-----+ +-----+
|NFQ#0| |NFQ#1| |NFQ#2| |NFQ#3|
+-----+ +-----+ +-----+ +-----+
^ ^ ^ ^
| |NFQUEUE | |
+ + + +
+-----+ +-----+ +-----+ +-----+
|rx-0 | |rx-1 | |rx-2 | |rx-3 |
+-----+ +-----+ +-----+ +-----+
The NFQUEUEs not necessarily have to start with number 0, setups with
less NFQUEUEs than packet-handling CPUs are not a problem as well.
This patch extends the NFQUEUE target to accept a new
NFQ_FLAG_CPU_FANOUT flag. If this is specified the target uses the
CPU index for determining the NFQUEUE being used. I have to introduce
rev3 for this. The 'flags' are folded into _v2 'bypass'.
By changing the way which queue is assigned, I'm able to improve the
performance if the processes reading on the NFQUEUs are pinned
correctly.
Signed-off-by: Holger Eitzenberger <holger@eitzenberger.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/xt_NFQUEUE.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 817f9e9f2b16..a287ef262d41 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c | |||
@@ -108,7 +108,7 @@ nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) | |||
108 | 108 | ||
109 | static int nfqueue_tg_check(const struct xt_tgchk_param *par) | 109 | static int nfqueue_tg_check(const struct xt_tgchk_param *par) |
110 | { | 110 | { |
111 | const struct xt_NFQ_info_v2 *info = par->targinfo; | 111 | const struct xt_NFQ_info_v3 *info = par->targinfo; |
112 | u32 maxid; | 112 | u32 maxid; |
113 | 113 | ||
114 | if (unlikely(!rnd_inited)) { | 114 | if (unlikely(!rnd_inited)) { |
@@ -125,11 +125,39 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par) | |||
125 | info->queues_total, maxid); | 125 | info->queues_total, maxid); |
126 | return -ERANGE; | 126 | return -ERANGE; |
127 | } | 127 | } |
128 | if (par->target->revision == 2 && info->bypass > 1) | 128 | if (par->target->revision == 2 && info->flags > 1) |
129 | return -EINVAL; | ||
130 | if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK) | ||
129 | return -EINVAL; | 131 | return -EINVAL; |
132 | |||
130 | return 0; | 133 | return 0; |
131 | } | 134 | } |
132 | 135 | ||
136 | static unsigned int | ||
137 | nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) | ||
138 | { | ||
139 | const struct xt_NFQ_info_v3 *info = par->targinfo; | ||
140 | u32 queue = info->queuenum; | ||
141 | |||
142 | if (info->queues_total > 1) { | ||
143 | if (info->flags & NFQ_FLAG_CPU_FANOUT) { | ||
144 | int cpu = smp_processor_id(); | ||
145 | |||
146 | queue = info->queuenum + cpu % info->queues_total; | ||
147 | } else { | ||
148 | if (par->family == NFPROTO_IPV4) | ||
149 | queue = (((u64) hash_v4(skb) * info->queues_total) >> | ||
150 | 32) + queue; | ||
151 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
152 | else if (par->family == NFPROTO_IPV6) | ||
153 | queue = (((u64) hash_v6(skb) * info->queues_total) >> | ||
154 | 32) + queue; | ||
155 | #endif | ||
156 | } | ||
157 | } | ||
158 | return NF_QUEUE_NR(queue); | ||
159 | } | ||
160 | |||
133 | static struct xt_target nfqueue_tg_reg[] __read_mostly = { | 161 | static struct xt_target nfqueue_tg_reg[] __read_mostly = { |
134 | { | 162 | { |
135 | .name = "NFQUEUE", | 163 | .name = "NFQUEUE", |
@@ -156,6 +184,15 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = { | |||
156 | .targetsize = sizeof(struct xt_NFQ_info_v2), | 184 | .targetsize = sizeof(struct xt_NFQ_info_v2), |
157 | .me = THIS_MODULE, | 185 | .me = THIS_MODULE, |
158 | }, | 186 | }, |
187 | { | ||
188 | .name = "NFQUEUE", | ||
189 | .revision = 3, | ||
190 | .family = NFPROTO_UNSPEC, | ||
191 | .checkentry = nfqueue_tg_check, | ||
192 | .target = nfqueue_tg_v3, | ||
193 | .targetsize = sizeof(struct xt_NFQ_info_v3), | ||
194 | .me = THIS_MODULE, | ||
195 | }, | ||
159 | }; | 196 | }; |
160 | 197 | ||
161 | static int __init nfqueue_tg_init(void) | 198 | static int __init nfqueue_tg_init(void) |