Skip to content

Commit fe6092e

Browse files
kaberDavid S. Miller
authored andcommitted
[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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c15bf6e commit fe6092e

File tree

1 file changed

+37
-12
lines changed

1 file changed

+37
-12
lines changed

net/ipv4/netfilter/nf_nat_helper.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
153153
const char *rep_buffer,
154154
unsigned int rep_len)
155155
{
156+
struct rtable *rt = (struct rtable *)(*pskb)->dst;
156157
struct iphdr *iph;
157158
struct tcphdr *tcph;
158159
int oldlen, datalen;
@@ -176,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
176177

177178
datalen = (*pskb)->len - iph->ihl*4;
178179
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
179-
tcph->check = 0;
180-
tcph->check = tcp_v4_check(datalen,
181-
iph->saddr, iph->daddr,
182-
csum_partial((char *)tcph,
183-
datalen, 0));
180+
if (!(rt->rt_flags & RTCF_LOCAL) &&
181+
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
182+
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
183+
(*pskb)->csum_start = skb_headroom(*pskb) +
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+
}
184196
} else
185197
nf_proto_csum_replace2(&tcph->check, *pskb,
186198
htons(oldlen), htons(datalen), 1);
@@ -217,6 +229,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
217229
const char *rep_buffer,
218230
unsigned int rep_len)
219231
{
232+
struct rtable *rt = (struct rtable *)(*pskb)->dst;
220233
struct iphdr *iph;
221234
struct udphdr *udph;
222235
int datalen, oldlen;
@@ -251,13 +264,25 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
251264
return 1;
252265

253266
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
254-
udph->check = 0;
255-
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
256-
datalen, IPPROTO_UDP,
257-
csum_partial((char *)udph,
258-
datalen, 0));
259-
if (!udph->check)
260-
udph->check = CSUM_MANGLED_0;
267+
if (!(rt->rt_flags & RTCF_LOCAL) &&
268+
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
269+
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
270+
(*pskb)->csum_start = skb_headroom(*pskb) +
271+
skb_network_offset(*pskb) +
272+
iph->ihl * 4;
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+
}
261286
} else
262287
nf_proto_csum_replace2(&udph->check, *pskb,
263288
htons(oldlen), htons(datalen), 1);

0 commit comments

Comments
 (0)