aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulius Volz <juliusv@google.com>2008-09-02 09:55:42 -0400
committerSimon Horman <horms@verge.net.au>2008-09-04 21:17:07 -0400
commit0bbdd42b7efa66685b6d74701bcde3a596a3a59d (patch)
tree98b1cc6fc7b856768b7923f2747e64c2ccc7878b /net
parent3b047d9d0407e78a52f009835a0e26cb62edb8c7 (diff)
IPVS: Extend protocol DNAT/SNAT and state handlers
Extend protocol DNAT/SNAT and state handlers to work with IPv6. Also change/introduce new checksumming helper functions for this. Signed-off-by: Julius Volz <juliusv@google.com> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c85
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c82
2 files changed, 131 insertions, 36 deletions
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 9211afa8f303..3daae43ae44b 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -114,11 +114,21 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
114 114
115 115
116static inline void 116static inline void
117tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip, 117tcp_fast_csum_update(int af, struct tcphdr *tcph,
118 const union nf_inet_addr *oldip,
119 const union nf_inet_addr *newip,
118 __be16 oldport, __be16 newport) 120 __be16 oldport, __be16 newport)
119{ 121{
122#ifdef CONFIG_IP_VS_IPV6
123 if (af == AF_INET6)
124 tcph->check =
125 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
126 ip_vs_check_diff2(oldport, newport,
127 ~csum_unfold(tcph->check))));
128 else
129#endif
120 tcph->check = 130 tcph->check =
121 csum_fold(ip_vs_check_diff4(oldip, newip, 131 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
122 ip_vs_check_diff2(oldport, newport, 132 ip_vs_check_diff2(oldport, newport,
123 ~csum_unfold(tcph->check)))); 133 ~csum_unfold(tcph->check))));
124} 134}
@@ -129,7 +139,14 @@ tcp_snat_handler(struct sk_buff *skb,
129 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 139 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
130{ 140{
131 struct tcphdr *tcph; 141 struct tcphdr *tcph;
132 const unsigned int tcphoff = ip_hdrlen(skb); 142 unsigned int tcphoff;
143
144#ifdef CONFIG_IP_VS_IPV6
145 if (cp->af == AF_INET6)
146 tcphoff = sizeof(struct ipv6hdr);
147 else
148#endif
149 tcphoff = ip_hdrlen(skb);
133 150
134 /* csum_check requires unshared skb */ 151 /* csum_check requires unshared skb */
135 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph))) 152 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -137,7 +154,7 @@ tcp_snat_handler(struct sk_buff *skb,
137 154
138 if (unlikely(cp->app != NULL)) { 155 if (unlikely(cp->app != NULL)) {
139 /* Some checks before mangling */ 156 /* Some checks before mangling */
140 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp)) 157 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
141 return 0; 158 return 0;
142 159
143 /* Call application helper if needed */ 160 /* Call application helper if needed */
@@ -145,13 +162,13 @@ tcp_snat_handler(struct sk_buff *skb,
145 return 0; 162 return 0;
146 } 163 }
147 164
148 tcph = (void *)ip_hdr(skb) + tcphoff; 165 tcph = (void *)skb_network_header(skb) + tcphoff;
149 tcph->source = cp->vport; 166 tcph->source = cp->vport;
150 167
151 /* Adjust TCP checksums */ 168 /* Adjust TCP checksums */
152 if (!cp->app) { 169 if (!cp->app) {
153 /* Only port and addr are changed, do fast csum update */ 170 /* Only port and addr are changed, do fast csum update */
154 tcp_fast_csum_update(tcph, cp->daddr.ip, cp->vaddr.ip, 171 tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
155 cp->dport, cp->vport); 172 cp->dport, cp->vport);
156 if (skb->ip_summed == CHECKSUM_COMPLETE) 173 if (skb->ip_summed == CHECKSUM_COMPLETE)
157 skb->ip_summed = CHECKSUM_NONE; 174 skb->ip_summed = CHECKSUM_NONE;
@@ -159,9 +176,20 @@ tcp_snat_handler(struct sk_buff *skb,
159 /* full checksum calculation */ 176 /* full checksum calculation */
160 tcph->check = 0; 177 tcph->check = 0;
161 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 178 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
162 tcph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip, 179#ifdef CONFIG_IP_VS_IPV6
163 skb->len - tcphoff, 180 if (cp->af == AF_INET6)
164 cp->protocol, skb->csum); 181 tcph->check = csum_ipv6_magic(&cp->vaddr.in6,
182 &cp->caddr.in6,
183 skb->len - tcphoff,
184 cp->protocol, skb->csum);
185 else
186#endif
187 tcph->check = csum_tcpudp_magic(cp->vaddr.ip,
188 cp->caddr.ip,
189 skb->len - tcphoff,
190 cp->protocol,
191 skb->csum);
192
165 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", 193 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
166 pp->name, tcph->check, 194 pp->name, tcph->check,
167 (char*)&(tcph->check) - (char*)tcph); 195 (char*)&(tcph->check) - (char*)tcph);
@@ -175,7 +203,14 @@ tcp_dnat_handler(struct sk_buff *skb,
175 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 203 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
176{ 204{
177 struct tcphdr *tcph; 205 struct tcphdr *tcph;
178 const unsigned int tcphoff = ip_hdrlen(skb); 206 unsigned int tcphoff;
207
208#ifdef CONFIG_IP_VS_IPV6
209 if (cp->af == AF_INET6)
210 tcphoff = sizeof(struct ipv6hdr);
211 else
212#endif
213 tcphoff = ip_hdrlen(skb);
179 214
180 /* csum_check requires unshared skb */ 215 /* csum_check requires unshared skb */
181 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph))) 216 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -183,7 +218,7 @@ tcp_dnat_handler(struct sk_buff *skb,
183 218
184 if (unlikely(cp->app != NULL)) { 219 if (unlikely(cp->app != NULL)) {
185 /* Some checks before mangling */ 220 /* Some checks before mangling */
186 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp)) 221 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
187 return 0; 222 return 0;
188 223
189 /* 224 /*
@@ -194,7 +229,7 @@ tcp_dnat_handler(struct sk_buff *skb,
194 return 0; 229 return 0;
195 } 230 }
196 231
197 tcph = (void *)ip_hdr(skb) + tcphoff; 232 tcph = (void *)skb_network_header(skb) + tcphoff;
198 tcph->dest = cp->dport; 233 tcph->dest = cp->dport;
199 234
200 /* 235 /*
@@ -202,7 +237,7 @@ tcp_dnat_handler(struct sk_buff *skb,
202 */ 237 */
203 if (!cp->app) { 238 if (!cp->app) {
204 /* Only port and addr are changed, do fast csum update */ 239 /* Only port and addr are changed, do fast csum update */
205 tcp_fast_csum_update(tcph, cp->vaddr.ip, cp->daddr.ip, 240 tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
206 cp->vport, cp->dport); 241 cp->vport, cp->dport);
207 if (skb->ip_summed == CHECKSUM_COMPLETE) 242 if (skb->ip_summed == CHECKSUM_COMPLETE)
208 skb->ip_summed = CHECKSUM_NONE; 243 skb->ip_summed = CHECKSUM_NONE;
@@ -210,9 +245,19 @@ tcp_dnat_handler(struct sk_buff *skb,
210 /* full checksum calculation */ 245 /* full checksum calculation */
211 tcph->check = 0; 246 tcph->check = 0;
212 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 247 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
213 tcph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip, 248#ifdef CONFIG_IP_VS_IPV6
214 skb->len - tcphoff, 249 if (cp->af == AF_INET6)
215 cp->protocol, skb->csum); 250 tcph->check = csum_ipv6_magic(&cp->caddr.in6,
251 &cp->daddr.in6,
252 skb->len - tcphoff,
253 cp->protocol, skb->csum);
254 else
255#endif
256 tcph->check = csum_tcpudp_magic(cp->caddr.ip,
257 cp->daddr.ip,
258 skb->len - tcphoff,
259 cp->protocol,
260 skb->csum);
216 skb->ip_summed = CHECKSUM_UNNECESSARY; 261 skb->ip_summed = CHECKSUM_UNNECESSARY;
217 } 262 }
218 return 1; 263 return 1;
@@ -487,7 +532,13 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
487{ 532{
488 struct tcphdr _tcph, *th; 533 struct tcphdr _tcph, *th;
489 534
490 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 535#ifdef CONFIG_IP_VS_IPV6
536 int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
537#else
538 int ihl = ip_hdrlen(skb);
539#endif
540
541 th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);
491 if (th == NULL) 542 if (th == NULL)
492 return 0; 543 return 0;
493 544
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index d3a1b1f2d10d..6cca0ad8e325 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -120,13 +120,23 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
120 120
121 121
122static inline void 122static inline void
123udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip, 123udp_fast_csum_update(int af, struct udphdr *uhdr,
124 const union nf_inet_addr *oldip,
125 const union nf_inet_addr *newip,
124 __be16 oldport, __be16 newport) 126 __be16 oldport, __be16 newport)
125{ 127{
126 uhdr->check = 128#ifdef CONFIG_IP_VS_IPV6
127 csum_fold(ip_vs_check_diff4(oldip, newip, 129 if (af == AF_INET6)
128 ip_vs_check_diff2(oldport, newport, 130 uhdr->check =
129 ~csum_unfold(uhdr->check)))); 131 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
132 ip_vs_check_diff2(oldport, newport,
133 ~csum_unfold(uhdr->check))));
134 else
135#endif
136 uhdr->check =
137 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
138 ip_vs_check_diff2(oldport, newport,
139 ~csum_unfold(uhdr->check))));
130 if (!uhdr->check) 140 if (!uhdr->check)
131 uhdr->check = CSUM_MANGLED_0; 141 uhdr->check = CSUM_MANGLED_0;
132} 142}
@@ -136,7 +146,14 @@ udp_snat_handler(struct sk_buff *skb,
136 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 146 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
137{ 147{
138 struct udphdr *udph; 148 struct udphdr *udph;
139 const unsigned int udphoff = ip_hdrlen(skb); 149 unsigned int udphoff;
150
151#ifdef CONFIG_IP_VS_IPV6
152 if (cp->af == AF_INET6)
153 udphoff = sizeof(struct ipv6hdr);
154 else
155#endif
156 udphoff = ip_hdrlen(skb);
140 157
141 /* csum_check requires unshared skb */ 158 /* csum_check requires unshared skb */
142 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 159 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -144,7 +161,7 @@ udp_snat_handler(struct sk_buff *skb,
144 161
145 if (unlikely(cp->app != NULL)) { 162 if (unlikely(cp->app != NULL)) {
146 /* Some checks before mangling */ 163 /* Some checks before mangling */
147 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp)) 164 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
148 return 0; 165 return 0;
149 166
150 /* 167 /*
@@ -154,7 +171,7 @@ udp_snat_handler(struct sk_buff *skb,
154 return 0; 171 return 0;
155 } 172 }
156 173
157 udph = (void *)ip_hdr(skb) + udphoff; 174 udph = (void *)skb_network_header(skb) + udphoff;
158 udph->source = cp->vport; 175 udph->source = cp->vport;
159 176
160 /* 177 /*
@@ -162,7 +179,7 @@ udp_snat_handler(struct sk_buff *skb,
162 */ 179 */
163 if (!cp->app && (udph->check != 0)) { 180 if (!cp->app && (udph->check != 0)) {
164 /* Only port and addr are changed, do fast csum update */ 181 /* Only port and addr are changed, do fast csum update */
165 udp_fast_csum_update(udph, cp->daddr.ip, cp->vaddr.ip, 182 udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
166 cp->dport, cp->vport); 183 cp->dport, cp->vport);
167 if (skb->ip_summed == CHECKSUM_COMPLETE) 184 if (skb->ip_summed == CHECKSUM_COMPLETE)
168 skb->ip_summed = CHECKSUM_NONE; 185 skb->ip_summed = CHECKSUM_NONE;
@@ -170,9 +187,19 @@ udp_snat_handler(struct sk_buff *skb,
170 /* full checksum calculation */ 187 /* full checksum calculation */
171 udph->check = 0; 188 udph->check = 0;
172 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0); 189 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
173 udph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip, 190#ifdef CONFIG_IP_VS_IPV6
174 skb->len - udphoff, 191 if (cp->af == AF_INET6)
175 cp->protocol, skb->csum); 192 udph->check = csum_ipv6_magic(&cp->vaddr.in6,
193 &cp->caddr.in6,
194 skb->len - udphoff,
195 cp->protocol, skb->csum);
196 else
197#endif
198 udph->check = csum_tcpudp_magic(cp->vaddr.ip,
199 cp->caddr.ip,
200 skb->len - udphoff,
201 cp->protocol,
202 skb->csum);
176 if (udph->check == 0) 203 if (udph->check == 0)
177 udph->check = CSUM_MANGLED_0; 204 udph->check = CSUM_MANGLED_0;
178 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", 205 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
@@ -188,7 +215,14 @@ udp_dnat_handler(struct sk_buff *skb,
188 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 215 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
189{ 216{
190 struct udphdr *udph; 217 struct udphdr *udph;
191 unsigned int udphoff = ip_hdrlen(skb); 218 unsigned int udphoff;
219
220#ifdef CONFIG_IP_VS_IPV6
221 if (cp->af == AF_INET6)
222 udphoff = sizeof(struct ipv6hdr);
223 else
224#endif
225 udphoff = ip_hdrlen(skb);
192 226
193 /* csum_check requires unshared skb */ 227 /* csum_check requires unshared skb */
194 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 228 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -196,7 +230,7 @@ udp_dnat_handler(struct sk_buff *skb,
196 230
197 if (unlikely(cp->app != NULL)) { 231 if (unlikely(cp->app != NULL)) {
198 /* Some checks before mangling */ 232 /* Some checks before mangling */
199 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp)) 233 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
200 return 0; 234 return 0;
201 235
202 /* 236 /*
@@ -207,7 +241,7 @@ udp_dnat_handler(struct sk_buff *skb,
207 return 0; 241 return 0;
208 } 242 }
209 243
210 udph = (void *)ip_hdr(skb) + udphoff; 244 udph = (void *)skb_network_header(skb) + udphoff;
211 udph->dest = cp->dport; 245 udph->dest = cp->dport;
212 246
213 /* 247 /*
@@ -215,7 +249,7 @@ udp_dnat_handler(struct sk_buff *skb,
215 */ 249 */
216 if (!cp->app && (udph->check != 0)) { 250 if (!cp->app && (udph->check != 0)) {
217 /* Only port and addr are changed, do fast csum update */ 251 /* Only port and addr are changed, do fast csum update */
218 udp_fast_csum_update(udph, cp->vaddr.ip, cp->daddr.ip, 252 udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
219 cp->vport, cp->dport); 253 cp->vport, cp->dport);
220 if (skb->ip_summed == CHECKSUM_COMPLETE) 254 if (skb->ip_summed == CHECKSUM_COMPLETE)
221 skb->ip_summed = CHECKSUM_NONE; 255 skb->ip_summed = CHECKSUM_NONE;
@@ -223,9 +257,19 @@ udp_dnat_handler(struct sk_buff *skb,
223 /* full checksum calculation */ 257 /* full checksum calculation */
224 udph->check = 0; 258 udph->check = 0;
225 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0); 259 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
226 udph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip, 260#ifdef CONFIG_IP_VS_IPV6
227 skb->len - udphoff, 261 if (cp->af == AF_INET6)
228 cp->protocol, skb->csum); 262 udph->check = csum_ipv6_magic(&cp->caddr.in6,
263 &cp->daddr.in6,
264 skb->len - udphoff,
265 cp->protocol, skb->csum);
266 else
267#endif
268 udph->check = csum_tcpudp_magic(cp->caddr.ip,
269 cp->daddr.ip,
270 skb->len - udphoff,
271 cp->protocol,
272 skb->csum);
229 if (udph->check == 0) 273 if (udph->check == 0)
230 udph->check = CSUM_MANGLED_0; 274 udph->check = CSUM_MANGLED_0;
231 skb->ip_summed = CHECKSUM_UNNECESSARY; 275 skb->ip_summed = CHECKSUM_UNNECESSARY;