aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2010-10-17 09:17:20 -0400
committerSimon Horman <horms@verge.net.au>2010-10-21 04:50:02 -0400
commit8b27b10f5863a5b63e46304a71aa01463d1efac4 (patch)
tree89f5db8881b0297cda00cad3c2cdedf685e2757f /net/netfilter
parent5bc9068e9d962ca6b8bec3f0eb6f60ab4dee1d04 (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.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c31
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c31
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;