diff options
author | Patrick McHardy <kaber@trash.net> | 2007-04-13 01:15:50 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:28:59 -0400 |
commit | fe6092ea0019cbba5263a915c9ce9f2bf383209e (patch) | |
tree | 0da8554466720878ce6fec639eebe7ea2e7ec96e /net/ipv4 | |
parent | c15bf6e699f4c366f2d1e19ac5d7add21c6b5a19 (diff) |
[NETFILTER]: nf_nat: use HW checksumming when possible
When mangling packets forwarded to a HW checksumming capable device,
offload recalculation of the checksum instead of doing it in software.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_helper.c | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 8a40fbe842b7..15b6e5ce3a04 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c | |||
@@ -153,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb, | |||
153 | const char *rep_buffer, | 153 | const char *rep_buffer, |
154 | unsigned int rep_len) | 154 | unsigned int rep_len) |
155 | { | 155 | { |
156 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
156 | struct iphdr *iph; | 157 | struct iphdr *iph; |
157 | struct tcphdr *tcph; | 158 | struct tcphdr *tcph; |
158 | int oldlen, datalen; | 159 | int oldlen, datalen; |
@@ -176,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb, | |||
176 | 177 | ||
177 | datalen = (*pskb)->len - iph->ihl*4; | 178 | datalen = (*pskb)->len - iph->ihl*4; |
178 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | 179 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { |
179 | tcph->check = 0; | 180 | if (!(rt->rt_flags & RTCF_LOCAL) && |
180 | tcph->check = tcp_v4_check(datalen, | 181 | (*pskb)->dev->features & NETIF_F_ALL_CSUM) { |
181 | iph->saddr, iph->daddr, | 182 | (*pskb)->ip_summed = CHECKSUM_PARTIAL; |
182 | csum_partial((char *)tcph, | 183 | (*pskb)->csum_start = skb_headroom(*pskb) + |
183 | datalen, 0)); | 184 | skb_network_offset(*pskb) + |
185 | iph->ihl * 4; | ||
186 | (*pskb)->csum_offset = offsetof(struct tcphdr, check); | ||
187 | tcph->check = ~tcp_v4_check(datalen, | ||
188 | iph->saddr, iph->daddr, 0); | ||
189 | } else { | ||
190 | tcph->check = 0; | ||
191 | tcph->check = tcp_v4_check(datalen, | ||
192 | iph->saddr, iph->daddr, | ||
193 | csum_partial((char *)tcph, | ||
194 | datalen, 0)); | ||
195 | } | ||
184 | } else | 196 | } else |
185 | nf_proto_csum_replace2(&tcph->check, *pskb, | 197 | nf_proto_csum_replace2(&tcph->check, *pskb, |
186 | htons(oldlen), htons(datalen), 1); | 198 | htons(oldlen), htons(datalen), 1); |
@@ -217,6 +229,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, | |||
217 | const char *rep_buffer, | 229 | const char *rep_buffer, |
218 | unsigned int rep_len) | 230 | unsigned int rep_len) |
219 | { | 231 | { |
232 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
220 | struct iphdr *iph; | 233 | struct iphdr *iph; |
221 | struct udphdr *udph; | 234 | struct udphdr *udph; |
222 | int datalen, oldlen; | 235 | int datalen, oldlen; |
@@ -251,13 +264,25 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, | |||
251 | return 1; | 264 | return 1; |
252 | 265 | ||
253 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | 266 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { |
254 | udph->check = 0; | 267 | if (!(rt->rt_flags & RTCF_LOCAL) && |
255 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | 268 | (*pskb)->dev->features & NETIF_F_ALL_CSUM) { |
256 | datalen, IPPROTO_UDP, | 269 | (*pskb)->ip_summed = CHECKSUM_PARTIAL; |
257 | csum_partial((char *)udph, | 270 | (*pskb)->csum_start = skb_headroom(*pskb) + |
258 | datalen, 0)); | 271 | skb_network_offset(*pskb) + |
259 | if (!udph->check) | 272 | iph->ihl * 4; |
260 | udph->check = CSUM_MANGLED_0; | 273 | (*pskb)->csum_offset = offsetof(struct udphdr, check); |
274 | udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
275 | datalen, IPPROTO_UDP, | ||
276 | 0); | ||
277 | } else { | ||
278 | udph->check = 0; | ||
279 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
280 | datalen, IPPROTO_UDP, | ||
281 | csum_partial((char *)udph, | ||
282 | datalen, 0)); | ||
283 | if (!udph->check) | ||
284 | udph->check = CSUM_MANGLED_0; | ||
285 | } | ||
261 | } else | 286 | } else |
262 | nf_proto_csum_replace2(&udph->check, *pskb, | 287 | nf_proto_csum_replace2(&udph->check, *pskb, |
263 | htons(oldlen), htons(datalen), 1); | 288 | htons(oldlen), htons(datalen), 1); |