aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipvs/ip_vs_proto_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_proto_udp.c')
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 5f2073e41cf6..e3ee26bd1de7 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -141,12 +141,34 @@ udp_fast_csum_update(int af, struct udphdr *uhdr,
141 uhdr->check = CSUM_MANGLED_0; 141 uhdr->check = CSUM_MANGLED_0;
142} 142}
143 143
144static inline void
145udp_partial_csum_update(int af, struct udphdr *uhdr,
146 const union nf_inet_addr *oldip,
147 const union nf_inet_addr *newip,
148 __be16 oldlen, __be16 newlen)
149{
150#ifdef CONFIG_IP_VS_IPV6
151 if (af == AF_INET6)
152 uhdr->check =
153 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
154 ip_vs_check_diff2(oldlen, newlen,
155 ~csum_unfold(uhdr->check))));
156 else
157#endif
158 uhdr->check =
159 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
160 ip_vs_check_diff2(oldlen, newlen,
161 ~csum_unfold(uhdr->check))));
162}
163
164
144static int 165static int
145udp_snat_handler(struct sk_buff *skb, 166udp_snat_handler(struct sk_buff *skb,
146 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 167 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
147{ 168{
148 struct udphdr *udph; 169 struct udphdr *udph;
149 unsigned int udphoff; 170 unsigned int udphoff;
171 int oldlen;
150 172
151#ifdef CONFIG_IP_VS_IPV6 173#ifdef CONFIG_IP_VS_IPV6
152 if (cp->af == AF_INET6) 174 if (cp->af == AF_INET6)
@@ -154,6 +176,7 @@ udp_snat_handler(struct sk_buff *skb,
154 else 176 else
155#endif 177#endif
156 udphoff = ip_hdrlen(skb); 178 udphoff = ip_hdrlen(skb);
179 oldlen = skb->len - udphoff;
157 180
158 /* csum_check requires unshared skb */ 181 /* csum_check requires unshared skb */
159 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 182 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -177,7 +200,11 @@ udp_snat_handler(struct sk_buff *skb,
177 /* 200 /*
178 * Adjust UDP checksums 201 * Adjust UDP checksums
179 */ 202 */
180 if (!cp->app && (udph->check != 0)) { 203 if (skb->ip_summed == CHECKSUM_PARTIAL) {
204 udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
205 htonl(oldlen),
206 htonl(skb->len - udphoff));
207 } else if (!cp->app && (udph->check != 0)) {
181 /* Only port and addr are changed, do fast csum update */ 208 /* Only port and addr are changed, do fast csum update */
182 udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, 209 udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
183 cp->dport, cp->vport); 210 cp->dport, cp->vport);
@@ -216,6 +243,7 @@ udp_dnat_handler(struct sk_buff *skb,
216{ 243{
217 struct udphdr *udph; 244 struct udphdr *udph;
218 unsigned int udphoff; 245 unsigned int udphoff;
246 int oldlen;
219 247
220#ifdef CONFIG_IP_VS_IPV6 248#ifdef CONFIG_IP_VS_IPV6
221 if (cp->af == AF_INET6) 249 if (cp->af == AF_INET6)
@@ -223,6 +251,7 @@ udp_dnat_handler(struct sk_buff *skb,
223 else 251 else
224#endif 252#endif
225 udphoff = ip_hdrlen(skb); 253 udphoff = ip_hdrlen(skb);
254 oldlen = skb->len - udphoff;
226 255
227 /* csum_check requires unshared skb */ 256 /* csum_check requires unshared skb */
228 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 257 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -247,7 +276,11 @@ udp_dnat_handler(struct sk_buff *skb,
247 /* 276 /*
248 * Adjust UDP checksums 277 * Adjust UDP checksums
249 */ 278 */
250 if (!cp->app && (udph->check != 0)) { 279 if (skb->ip_summed == CHECKSUM_PARTIAL) {
280 udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
281 htonl(oldlen),
282 htonl(skb->len - udphoff));
283 } else if (!cp->app && (udph->check != 0)) {
251 /* Only port and addr are changed, do fast csum update */ 284 /* Only port and addr are changed, do fast csum update */
252 udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, 285 udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
253 cp->vport, cp->dport); 286 cp->vport, cp->dport);