Commit fe6092ea authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c15bf6e6
...@@ -153,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb, ...@@ -153,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
const char *rep_buffer, const char *rep_buffer,
unsigned int rep_len) unsigned int rep_len)
{ {
struct rtable *rt = (struct rtable *)(*pskb)->dst;
struct iphdr *iph; struct iphdr *iph;
struct tcphdr *tcph; struct tcphdr *tcph;
int oldlen, datalen; int oldlen, datalen;
...@@ -176,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb, ...@@ -176,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen = (*pskb)->len - iph->ihl*4; datalen = (*pskb)->len - iph->ihl*4;
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
(*pskb)->csum_start = skb_headroom(*pskb) +
skb_network_offset(*pskb) +
iph->ihl * 4;
(*pskb)->csum_offset = offsetof(struct tcphdr, check);
tcph->check = ~tcp_v4_check(datalen,
iph->saddr, iph->daddr, 0);
} else {
tcph->check = 0; tcph->check = 0;
tcph->check = tcp_v4_check(datalen, tcph->check = tcp_v4_check(datalen,
iph->saddr, iph->daddr, iph->saddr, iph->daddr,
csum_partial((char *)tcph, csum_partial((char *)tcph,
datalen, 0)); datalen, 0));
}
} else } else
nf_proto_csum_replace2(&tcph->check, *pskb, nf_proto_csum_replace2(&tcph->check, *pskb,
htons(oldlen), htons(datalen), 1); htons(oldlen), htons(datalen), 1);
...@@ -217,6 +229,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, ...@@ -217,6 +229,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
const char *rep_buffer, const char *rep_buffer,
unsigned int rep_len) unsigned int rep_len)
{ {
struct rtable *rt = (struct rtable *)(*pskb)->dst;
struct iphdr *iph; struct iphdr *iph;
struct udphdr *udph; struct udphdr *udph;
int datalen, oldlen; int datalen, oldlen;
...@@ -251,6 +264,17 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, ...@@ -251,6 +264,17 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
return 1; return 1;
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
(*pskb)->dev->features & NETIF_F_ALL_CSUM) {
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
(*pskb)->csum_start = skb_headroom(*pskb) +
skb_network_offset(*pskb) +
iph->ihl * 4;
(*pskb)->csum_offset = offsetof(struct udphdr, check);
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP,
0);
} else {
udph->check = 0; udph->check = 0;
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP, datalen, IPPROTO_UDP,
...@@ -258,6 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, ...@@ -258,6 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
datalen, 0)); datalen, 0));
if (!udph->check) if (!udph->check)
udph->check = CSUM_MANGLED_0; udph->check = CSUM_MANGLED_0;
}
} else } else
nf_proto_csum_replace2(&udph->check, *pskb, nf_proto_csum_replace2(&udph->check, *pskb,
htons(oldlen), htons(datalen), 1); htons(oldlen), htons(datalen), 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment