diff options
author | Julian Anastasov <ja@ssi.bg> | 2010-10-17 09:17:20 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2010-10-21 04:50:02 -0400 |
commit | 8b27b10f5863a5b63e46304a71aa01463d1efac4 (patch) | |
tree | 89f5db8881b0297cda00cad3c2cdedf685e2757f /net/netfilter | |
parent | 5bc9068e9d962ca6b8bec3f0eb6f60ab4dee1d04 (diff) |
ipvs: optimize checksums for apps
Avoid full checksum calculation for apps that can provide
info whether csum was broken after payload mangling. For now only
ip_vs_ftp mangles payload and it updates the csum, so the full
recalculation is avoided for all packets.
Add CHECKSUM_UNNECESSARY for snat_handler (TCP and UDP).
It is needed to support SNAT from local address for the case
when csum is fully recalculated.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ftp.c | 7 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_tcp.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 31 |
3 files changed, 56 insertions, 13 deletions
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 090889a3b3af..75455000ad1c 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
@@ -242,9 +242,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
242 | ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | 242 | ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo, |
243 | start-data, end-start, | 243 | start-data, end-start, |
244 | buf, buf_len); | 244 | buf, buf_len); |
245 | if (ret) | 245 | if (ret) { |
246 | ip_vs_nfct_expect_related(skb, ct, n_cp, | 246 | ip_vs_nfct_expect_related(skb, ct, n_cp, |
247 | IPPROTO_TCP, 0, 0); | 247 | IPPROTO_TCP, 0, 0); |
248 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
249 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
250 | /* csum is updated */ | ||
251 | ret = 1; | ||
252 | } | ||
248 | } | 253 | } |
249 | 254 | ||
250 | /* | 255 | /* |
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 318d011036db..64dc2954cf78 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c | |||
@@ -120,6 +120,7 @@ tcp_snat_handler(struct sk_buff *skb, | |||
120 | struct tcphdr *tcph; | 120 | struct tcphdr *tcph; |
121 | unsigned int tcphoff; | 121 | unsigned int tcphoff; |
122 | int oldlen; | 122 | int oldlen; |
123 | int payload_csum = 0; | ||
123 | 124 | ||
124 | #ifdef CONFIG_IP_VS_IPV6 | 125 | #ifdef CONFIG_IP_VS_IPV6 |
125 | if (cp->af == AF_INET6) | 126 | if (cp->af == AF_INET6) |
@@ -134,13 +135,20 @@ tcp_snat_handler(struct sk_buff *skb, | |||
134 | return 0; | 135 | return 0; |
135 | 136 | ||
136 | if (unlikely(cp->app != NULL)) { | 137 | if (unlikely(cp->app != NULL)) { |
138 | int ret; | ||
139 | |||
137 | /* Some checks before mangling */ | 140 | /* Some checks before mangling */ |
138 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) | 141 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) |
139 | return 0; | 142 | return 0; |
140 | 143 | ||
141 | /* Call application helper if needed */ | 144 | /* Call application helper if needed */ |
142 | if (!ip_vs_app_pkt_out(cp, skb)) | 145 | if (!(ret = ip_vs_app_pkt_out(cp, skb))) |
143 | return 0; | 146 | return 0; |
147 | /* ret=2: csum update is needed after payload mangling */ | ||
148 | if (ret == 1) | ||
149 | oldlen = skb->len - tcphoff; | ||
150 | else | ||
151 | payload_csum = 1; | ||
144 | } | 152 | } |
145 | 153 | ||
146 | tcph = (void *)skb_network_header(skb) + tcphoff; | 154 | tcph = (void *)skb_network_header(skb) + tcphoff; |
@@ -151,12 +159,13 @@ tcp_snat_handler(struct sk_buff *skb, | |||
151 | tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, | 159 | tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, |
152 | htons(oldlen), | 160 | htons(oldlen), |
153 | htons(skb->len - tcphoff)); | 161 | htons(skb->len - tcphoff)); |
154 | } else if (!cp->app) { | 162 | } else if (!payload_csum) { |
155 | /* Only port and addr are changed, do fast csum update */ | 163 | /* Only port and addr are changed, do fast csum update */ |
156 | tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, | 164 | tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, |
157 | cp->dport, cp->vport); | 165 | cp->dport, cp->vport); |
158 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 166 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
159 | skb->ip_summed = CHECKSUM_NONE; | 167 | skb->ip_summed = (cp->app && pp->csum_check) ? |
168 | CHECKSUM_UNNECESSARY : CHECKSUM_NONE; | ||
160 | } else { | 169 | } else { |
161 | /* full checksum calculation */ | 170 | /* full checksum calculation */ |
162 | tcph->check = 0; | 171 | tcph->check = 0; |
@@ -174,6 +183,7 @@ tcp_snat_handler(struct sk_buff *skb, | |||
174 | skb->len - tcphoff, | 183 | skb->len - tcphoff, |
175 | cp->protocol, | 184 | cp->protocol, |
176 | skb->csum); | 185 | skb->csum); |
186 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
177 | 187 | ||
178 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", | 188 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", |
179 | pp->name, tcph->check, | 189 | pp->name, tcph->check, |
@@ -190,6 +200,7 @@ tcp_dnat_handler(struct sk_buff *skb, | |||
190 | struct tcphdr *tcph; | 200 | struct tcphdr *tcph; |
191 | unsigned int tcphoff; | 201 | unsigned int tcphoff; |
192 | int oldlen; | 202 | int oldlen; |
203 | int payload_csum = 0; | ||
193 | 204 | ||
194 | #ifdef CONFIG_IP_VS_IPV6 | 205 | #ifdef CONFIG_IP_VS_IPV6 |
195 | if (cp->af == AF_INET6) | 206 | if (cp->af == AF_INET6) |
@@ -204,6 +215,8 @@ tcp_dnat_handler(struct sk_buff *skb, | |||
204 | return 0; | 215 | return 0; |
205 | 216 | ||
206 | if (unlikely(cp->app != NULL)) { | 217 | if (unlikely(cp->app != NULL)) { |
218 | int ret; | ||
219 | |||
207 | /* Some checks before mangling */ | 220 | /* Some checks before mangling */ |
208 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) | 221 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) |
209 | return 0; | 222 | return 0; |
@@ -212,8 +225,13 @@ tcp_dnat_handler(struct sk_buff *skb, | |||
212 | * Attempt ip_vs_app call. | 225 | * Attempt ip_vs_app call. |
213 | * It will fix ip_vs_conn and iph ack_seq stuff | 226 | * It will fix ip_vs_conn and iph ack_seq stuff |
214 | */ | 227 | */ |
215 | if (!ip_vs_app_pkt_in(cp, skb)) | 228 | if (!(ret = ip_vs_app_pkt_in(cp, skb))) |
216 | return 0; | 229 | return 0; |
230 | /* ret=2: csum update is needed after payload mangling */ | ||
231 | if (ret == 1) | ||
232 | oldlen = skb->len - tcphoff; | ||
233 | else | ||
234 | payload_csum = 1; | ||
217 | } | 235 | } |
218 | 236 | ||
219 | tcph = (void *)skb_network_header(skb) + tcphoff; | 237 | tcph = (void *)skb_network_header(skb) + tcphoff; |
@@ -226,12 +244,13 @@ tcp_dnat_handler(struct sk_buff *skb, | |||
226 | tcp_partial_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr, | 244 | tcp_partial_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr, |
227 | htons(oldlen), | 245 | htons(oldlen), |
228 | htons(skb->len - tcphoff)); | 246 | htons(skb->len - tcphoff)); |
229 | } else if (!cp->app) { | 247 | } else if (!payload_csum) { |
230 | /* Only port and addr are changed, do fast csum update */ | 248 | /* Only port and addr are changed, do fast csum update */ |
231 | tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr, | 249 | tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr, |
232 | cp->vport, cp->dport); | 250 | cp->vport, cp->dport); |
233 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 251 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
234 | skb->ip_summed = CHECKSUM_NONE; | 252 | skb->ip_summed = (cp->app && pp->csum_check) ? |
253 | CHECKSUM_UNNECESSARY : CHECKSUM_NONE; | ||
235 | } else { | 254 | } else { |
236 | /* full checksum calculation */ | 255 | /* full checksum calculation */ |
237 | tcph->check = 0; | 256 | tcph->check = 0; |
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index f9290893bd93..9c558c40bfbb 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c | |||
@@ -121,6 +121,7 @@ udp_snat_handler(struct sk_buff *skb, | |||
121 | struct udphdr *udph; | 121 | struct udphdr *udph; |
122 | unsigned int udphoff; | 122 | unsigned int udphoff; |
123 | int oldlen; | 123 | int oldlen; |
124 | int payload_csum = 0; | ||
124 | 125 | ||
125 | #ifdef CONFIG_IP_VS_IPV6 | 126 | #ifdef CONFIG_IP_VS_IPV6 |
126 | if (cp->af == AF_INET6) | 127 | if (cp->af == AF_INET6) |
@@ -135,6 +136,8 @@ udp_snat_handler(struct sk_buff *skb, | |||
135 | return 0; | 136 | return 0; |
136 | 137 | ||
137 | if (unlikely(cp->app != NULL)) { | 138 | if (unlikely(cp->app != NULL)) { |
139 | int ret; | ||
140 | |||
138 | /* Some checks before mangling */ | 141 | /* Some checks before mangling */ |
139 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) | 142 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) |
140 | return 0; | 143 | return 0; |
@@ -142,8 +145,13 @@ udp_snat_handler(struct sk_buff *skb, | |||
142 | /* | 145 | /* |
143 | * Call application helper if needed | 146 | * Call application helper if needed |
144 | */ | 147 | */ |
145 | if (!ip_vs_app_pkt_out(cp, skb)) | 148 | if (!(ret = ip_vs_app_pkt_out(cp, skb))) |
146 | return 0; | 149 | return 0; |
150 | /* ret=2: csum update is needed after payload mangling */ | ||
151 | if (ret == 1) | ||
152 | oldlen = skb->len - udphoff; | ||
153 | else | ||
154 | payload_csum = 1; | ||
147 | } | 155 | } |
148 | 156 | ||
149 | udph = (void *)skb_network_header(skb) + udphoff; | 157 | udph = (void *)skb_network_header(skb) + udphoff; |
@@ -156,12 +164,13 @@ udp_snat_handler(struct sk_buff *skb, | |||
156 | udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, | 164 | udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, |
157 | htons(oldlen), | 165 | htons(oldlen), |
158 | htons(skb->len - udphoff)); | 166 | htons(skb->len - udphoff)); |
159 | } else if (!cp->app && (udph->check != 0)) { | 167 | } else if (!payload_csum && (udph->check != 0)) { |
160 | /* Only port and addr are changed, do fast csum update */ | 168 | /* Only port and addr are changed, do fast csum update */ |
161 | udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, | 169 | udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, |
162 | cp->dport, cp->vport); | 170 | cp->dport, cp->vport); |
163 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 171 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
164 | skb->ip_summed = CHECKSUM_NONE; | 172 | skb->ip_summed = (cp->app && pp->csum_check) ? |
173 | CHECKSUM_UNNECESSARY : CHECKSUM_NONE; | ||
165 | } else { | 174 | } else { |
166 | /* full checksum calculation */ | 175 | /* full checksum calculation */ |
167 | udph->check = 0; | 176 | udph->check = 0; |
@@ -181,6 +190,7 @@ udp_snat_handler(struct sk_buff *skb, | |||
181 | skb->csum); | 190 | skb->csum); |
182 | if (udph->check == 0) | 191 | if (udph->check == 0) |
183 | udph->check = CSUM_MANGLED_0; | 192 | udph->check = CSUM_MANGLED_0; |
193 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
184 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", | 194 | IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", |
185 | pp->name, udph->check, | 195 | pp->name, udph->check, |
186 | (char*)&(udph->check) - (char*)udph); | 196 | (char*)&(udph->check) - (char*)udph); |
@@ -196,6 +206,7 @@ udp_dnat_handler(struct sk_buff *skb, | |||
196 | struct udphdr *udph; | 206 | struct udphdr *udph; |
197 | unsigned int udphoff; | 207 | unsigned int udphoff; |
198 | int oldlen; | 208 | int oldlen; |
209 | int payload_csum = 0; | ||
199 | 210 | ||
200 | #ifdef CONFIG_IP_VS_IPV6 | 211 | #ifdef CONFIG_IP_VS_IPV6 |
201 | if (cp->af == AF_INET6) | 212 | if (cp->af == AF_INET6) |
@@ -210,6 +221,8 @@ udp_dnat_handler(struct sk_buff *skb, | |||
210 | return 0; | 221 | return 0; |
211 | 222 | ||
212 | if (unlikely(cp->app != NULL)) { | 223 | if (unlikely(cp->app != NULL)) { |
224 | int ret; | ||
225 | |||
213 | /* Some checks before mangling */ | 226 | /* Some checks before mangling */ |
214 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) | 227 | if (pp->csum_check && !pp->csum_check(cp->af, skb, pp)) |
215 | return 0; | 228 | return 0; |
@@ -218,8 +231,13 @@ udp_dnat_handler(struct sk_buff *skb, | |||
218 | * Attempt ip_vs_app call. | 231 | * Attempt ip_vs_app call. |
219 | * It will fix ip_vs_conn | 232 | * It will fix ip_vs_conn |
220 | */ | 233 | */ |
221 | if (!ip_vs_app_pkt_in(cp, skb)) | 234 | if (!(ret = ip_vs_app_pkt_in(cp, skb))) |
222 | return 0; | 235 | return 0; |
236 | /* ret=2: csum update is needed after payload mangling */ | ||
237 | if (ret == 1) | ||
238 | oldlen = skb->len - udphoff; | ||
239 | else | ||
240 | payload_csum = 1; | ||
223 | } | 241 | } |
224 | 242 | ||
225 | udph = (void *)skb_network_header(skb) + udphoff; | 243 | udph = (void *)skb_network_header(skb) + udphoff; |
@@ -232,12 +250,13 @@ udp_dnat_handler(struct sk_buff *skb, | |||
232 | udp_partial_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, | 250 | udp_partial_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, |
233 | htons(oldlen), | 251 | htons(oldlen), |
234 | htons(skb->len - udphoff)); | 252 | htons(skb->len - udphoff)); |
235 | } else if (!cp->app && (udph->check != 0)) { | 253 | } else if (!payload_csum && (udph->check != 0)) { |
236 | /* Only port and addr are changed, do fast csum update */ | 254 | /* Only port and addr are changed, do fast csum update */ |
237 | udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, | 255 | udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, |
238 | cp->vport, cp->dport); | 256 | cp->vport, cp->dport); |
239 | if (skb->ip_summed == CHECKSUM_COMPLETE) | 257 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
240 | skb->ip_summed = CHECKSUM_NONE; | 258 | skb->ip_summed = (cp->app && pp->csum_check) ? |
259 | CHECKSUM_UNNECESSARY : CHECKSUM_NONE; | ||
241 | } else { | 260 | } else { |
242 | /* full checksum calculation */ | 261 | /* full checksum calculation */ |
243 | udph->check = 0; | 262 | udph->check = 0; |