diff options
author | Eric Dumazet <edumazet@google.com> | 2014-03-23 22:51:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-24 00:18:44 -0400 |
commit | 99f0b958b194f7d88973f1c2190d207e0a2c7e79 (patch) | |
tree | f76073a45af1840a773084b039c53f7b7db58fb5 /include/net/checksum.h | |
parent | 860b4042ddec744de52461f91c869630b1bb23c2 (diff) |
net: optimize csum_replace2()
When changing one 16bit value by another in IP header, we can adjust
the IP checksum by doing a simple operation described in RFC 1624, as
reminded by David.
csum_partial() is a complex function on x86_64, not really suited for
small number of checksummed bytes.
I spotted csum_partial() being in the top 20 most consuming functions
(more than 1 %) in a GRO workload, which was rather unexpected.
The caller was inet_gro_complete() doing a csum_replace2() when
building the new IP header for the GRO packet.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/checksum.h')
-rw-r--r-- | include/net/checksum.h | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/include/net/checksum.h b/include/net/checksum.h index 37a0e24adbe7..a28f4e0f6251 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h | |||
@@ -69,6 +69,19 @@ static inline __wsum csum_sub(__wsum csum, __wsum addend) | |||
69 | return csum_add(csum, ~addend); | 69 | return csum_add(csum, ~addend); |
70 | } | 70 | } |
71 | 71 | ||
72 | static inline __sum16 csum16_add(__sum16 csum, __be16 addend) | ||
73 | { | ||
74 | u16 res = (__force u16)csum; | ||
75 | |||
76 | res += (__force u16)addend; | ||
77 | return (__force __sum16)(res + (res < (__force u16)addend)); | ||
78 | } | ||
79 | |||
80 | static inline __sum16 csum16_sub(__sum16 csum, __be16 addend) | ||
81 | { | ||
82 | return csum16_add(csum, ~addend); | ||
83 | } | ||
84 | |||
72 | static inline __wsum | 85 | static inline __wsum |
73 | csum_block_add(__wsum csum, __wsum csum2, int offset) | 86 | csum_block_add(__wsum csum, __wsum csum2, int offset) |
74 | { | 87 | { |
@@ -112,9 +125,15 @@ static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) | |||
112 | *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); | 125 | *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); |
113 | } | 126 | } |
114 | 127 | ||
115 | static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to) | 128 | /* Implements RFC 1624 (Incremental Internet Checksum) |
129 | * 3. Discussion states : | ||
130 | * HC' = ~(~HC + ~m + m') | ||
131 | * m : old value of a 16bit field | ||
132 | * m' : new value of a 16bit field | ||
133 | */ | ||
134 | static inline void csum_replace2(__sum16 *sum, __be16 old, __be16 new) | ||
116 | { | 135 | { |
117 | csum_replace4(sum, (__force __be32)from, (__force __be32)to); | 136 | *sum = ~csum16_add(csum16_sub(~(*sum), old), new); |
118 | } | 137 | } |
119 | 138 | ||
120 | struct sk_buff; | 139 | struct sk_buff; |