Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+37 −12
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
			 const char *rep_buffer,
			 unsigned int rep_len)
{
	struct rtable *rt = (struct rtable *)(*pskb)->dst;
	struct iphdr *iph;
	struct tcphdr *tcph;
	int oldlen, datalen;
@@ -176,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,

	datalen = (*pskb)->len - iph->ihl*4;
	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 = tcp_v4_check(datalen,
						   iph->saddr, iph->daddr,
						   csum_partial((char *)tcph,
								datalen, 0));
		}
	} else
		nf_proto_csum_replace2(&tcph->check, *pskb,
				       htons(oldlen), htons(datalen), 1);
@@ -217,6 +229,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
			 const char *rep_buffer,
			 unsigned int rep_len)
{
	struct rtable *rt = (struct rtable *)(*pskb)->dst;
	struct iphdr *iph;
	struct udphdr *udph;
	int datalen, oldlen;
@@ -251,6 +264,17 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
		return 1;

	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 = csum_tcpudp_magic(iph->saddr, iph->daddr,
							datalen, IPPROTO_UDP,
@@ -258,6 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
								     datalen, 0));
			if (!udph->check)
				udph->check = CSUM_MANGLED_0;
		}
	} else
		nf_proto_csum_replace2(&udph->check, *pskb,
				       htons(oldlen), htons(datalen), 1);