diff options
author | Jesper Dangaard Brouer <brouer@redhat.com> | 2012-09-26 08:07:17 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2012-09-27 22:34:33 -0400 |
commit | d4383f04d145cce8b855c463f40020639ef83ea0 (patch) | |
tree | 7807b2b3114fc25c03eb3d3741f9b6d1b17aedfe /net/netfilter | |
parent | 2f74713d1436b7d2d0506ba1bc5f10915a73bbec (diff) |
ipvs: API change to avoid rescan of IPv6 exthdr
Reduce the number of times we scan/skip the IPv6 exthdrs.
This patch contains a lot of API changes. This is done, to avoid
repeating the scan of finding the IPv6 headers, via ipv6_find_hdr(),
which is called by ip_vs_fill_iph_skb().
Finding the IPv6 headers is done as early as possible, and passed on
as a pointer "struct ip_vs_iphdr *" to the affected functions.
This patch reduce/removes 19 calls to ip_vs_fill_iph_skb().
Notice, I have choosen, not to change the API of function
pointer "(*schedule)" (in struct ip_vs_scheduler) as it can be
used by external schedulers, via {un,}register_ip_vs_scheduler.
Only 4 out of 10 schedulers use info from ip_vs_iphdr*, and when
they do, they are only interested in iph->{s,d}addr.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-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_conn.c | 15 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 116 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 9 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_sctp.c | 42 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_tcp.c | 40 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 41 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 58 | ||||
-rw-r--r-- | net/netfilter/xt_ipvs.c | 2 |
8 files changed, 134 insertions, 189 deletions
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index d6c1c2636dd..30e764ad021 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
@@ -308,13 +308,12 @@ struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p) | |||
308 | static int | 308 | static int |
309 | ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, | 309 | ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, |
310 | const struct ip_vs_iphdr *iph, | 310 | const struct ip_vs_iphdr *iph, |
311 | unsigned int proto_off, int inverse, | 311 | int inverse, struct ip_vs_conn_param *p) |
312 | struct ip_vs_conn_param *p) | ||
313 | { | 312 | { |
314 | __be16 _ports[2], *pptr; | 313 | __be16 _ports[2], *pptr; |
315 | struct net *net = skb_net(skb); | 314 | struct net *net = skb_net(skb); |
316 | 315 | ||
317 | pptr = frag_safe_skb_hp(skb, proto_off, sizeof(_ports), _ports, iph); | 316 | pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); |
318 | if (pptr == NULL) | 317 | if (pptr == NULL) |
319 | return 1; | 318 | return 1; |
320 | 319 | ||
@@ -329,12 +328,11 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, | |||
329 | 328 | ||
330 | struct ip_vs_conn * | 329 | struct ip_vs_conn * |
331 | ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, | 330 | ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, |
332 | const struct ip_vs_iphdr *iph, | 331 | const struct ip_vs_iphdr *iph, int inverse) |
333 | unsigned int proto_off, int inverse) | ||
334 | { | 332 | { |
335 | struct ip_vs_conn_param p; | 333 | struct ip_vs_conn_param p; |
336 | 334 | ||
337 | if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p)) | 335 | if (ip_vs_conn_fill_param_proto(af, skb, iph, inverse, &p)) |
338 | return NULL; | 336 | return NULL; |
339 | 337 | ||
340 | return ip_vs_conn_in_get(&p); | 338 | return ip_vs_conn_in_get(&p); |
@@ -432,12 +430,11 @@ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p) | |||
432 | 430 | ||
433 | struct ip_vs_conn * | 431 | struct ip_vs_conn * |
434 | ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, | 432 | ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, |
435 | const struct ip_vs_iphdr *iph, | 433 | const struct ip_vs_iphdr *iph, int inverse) |
436 | unsigned int proto_off, int inverse) | ||
437 | { | 434 | { |
438 | struct ip_vs_conn_param p; | 435 | struct ip_vs_conn_param p; |
439 | 436 | ||
440 | if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p)) | 437 | if (ip_vs_conn_fill_param_proto(af, skb, iph, inverse, &p)) |
441 | return NULL; | 438 | return NULL; |
442 | 439 | ||
443 | return ip_vs_conn_out_get(&p); | 440 | return ip_vs_conn_out_get(&p); |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 19b89ff94cd..fb45640dc1f 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -222,11 +222,10 @@ ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc, | |||
222 | */ | 222 | */ |
223 | static struct ip_vs_conn * | 223 | static struct ip_vs_conn * |
224 | ip_vs_sched_persist(struct ip_vs_service *svc, | 224 | ip_vs_sched_persist(struct ip_vs_service *svc, |
225 | struct sk_buff *skb, | 225 | struct sk_buff *skb, __be16 src_port, __be16 dst_port, |
226 | __be16 src_port, __be16 dst_port, int *ignored) | 226 | int *ignored, struct ip_vs_iphdr *iph) |
227 | { | 227 | { |
228 | struct ip_vs_conn *cp = NULL; | 228 | struct ip_vs_conn *cp = NULL; |
229 | struct ip_vs_iphdr iph; | ||
230 | struct ip_vs_dest *dest; | 229 | struct ip_vs_dest *dest; |
231 | struct ip_vs_conn *ct; | 230 | struct ip_vs_conn *ct; |
232 | __be16 dport = 0; /* destination port to forward */ | 231 | __be16 dport = 0; /* destination port to forward */ |
@@ -236,20 +235,18 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
236 | union nf_inet_addr snet; /* source network of the client, | 235 | union nf_inet_addr snet; /* source network of the client, |
237 | after masking */ | 236 | after masking */ |
238 | 237 | ||
239 | ip_vs_fill_iph_skb(svc->af, skb, &iph); | ||
240 | |||
241 | /* Mask saddr with the netmask to adjust template granularity */ | 238 | /* Mask saddr with the netmask to adjust template granularity */ |
242 | #ifdef CONFIG_IP_VS_IPV6 | 239 | #ifdef CONFIG_IP_VS_IPV6 |
243 | if (svc->af == AF_INET6) | 240 | if (svc->af == AF_INET6) |
244 | ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask); | 241 | ipv6_addr_prefix(&snet.in6, &iph->saddr.in6, svc->netmask); |
245 | else | 242 | else |
246 | #endif | 243 | #endif |
247 | snet.ip = iph.saddr.ip & svc->netmask; | 244 | snet.ip = iph->saddr.ip & svc->netmask; |
248 | 245 | ||
249 | IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u " | 246 | IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u " |
250 | "mnet %s\n", | 247 | "mnet %s\n", |
251 | IP_VS_DBG_ADDR(svc->af, &iph.saddr), ntohs(src_port), | 248 | IP_VS_DBG_ADDR(svc->af, &iph->saddr), ntohs(src_port), |
252 | IP_VS_DBG_ADDR(svc->af, &iph.daddr), ntohs(dst_port), | 249 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), ntohs(dst_port), |
253 | IP_VS_DBG_ADDR(svc->af, &snet)); | 250 | IP_VS_DBG_ADDR(svc->af, &snet)); |
254 | 251 | ||
255 | /* | 252 | /* |
@@ -266,8 +263,8 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
266 | * is created for other persistent services. | 263 | * is created for other persistent services. |
267 | */ | 264 | */ |
268 | { | 265 | { |
269 | int protocol = iph.protocol; | 266 | int protocol = iph->protocol; |
270 | const union nf_inet_addr *vaddr = &iph.daddr; | 267 | const union nf_inet_addr *vaddr = &iph->daddr; |
271 | __be16 vport = 0; | 268 | __be16 vport = 0; |
272 | 269 | ||
273 | if (dst_port == svc->port) { | 270 | if (dst_port == svc->port) { |
@@ -342,14 +339,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
342 | dport = dest->port; | 339 | dport = dest->port; |
343 | 340 | ||
344 | flags = (svc->flags & IP_VS_SVC_F_ONEPACKET | 341 | flags = (svc->flags & IP_VS_SVC_F_ONEPACKET |
345 | && iph.protocol == IPPROTO_UDP)? | 342 | && iph->protocol == IPPROTO_UDP) ? |
346 | IP_VS_CONN_F_ONE_PACKET : 0; | 343 | IP_VS_CONN_F_ONE_PACKET : 0; |
347 | 344 | ||
348 | /* | 345 | /* |
349 | * Create a new connection according to the template | 346 | * Create a new connection according to the template |
350 | */ | 347 | */ |
351 | ip_vs_conn_fill_param(svc->net, svc->af, iph.protocol, &iph.saddr, | 348 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, &iph->saddr, |
352 | src_port, &iph.daddr, dst_port, ¶m); | 349 | src_port, &iph->daddr, dst_port, ¶m); |
353 | 350 | ||
354 | cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest, skb->mark); | 351 | cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest, skb->mark); |
355 | if (cp == NULL) { | 352 | if (cp == NULL) { |
@@ -392,22 +389,20 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
392 | */ | 389 | */ |
393 | struct ip_vs_conn * | 390 | struct ip_vs_conn * |
394 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | 391 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, |
395 | struct ip_vs_proto_data *pd, int *ignored) | 392 | struct ip_vs_proto_data *pd, int *ignored, |
393 | struct ip_vs_iphdr *iph) | ||
396 | { | 394 | { |
397 | struct ip_vs_protocol *pp = pd->pp; | 395 | struct ip_vs_protocol *pp = pd->pp; |
398 | struct ip_vs_conn *cp = NULL; | 396 | struct ip_vs_conn *cp = NULL; |
399 | struct ip_vs_iphdr iph; | ||
400 | struct ip_vs_dest *dest; | 397 | struct ip_vs_dest *dest; |
401 | __be16 _ports[2], *pptr; | 398 | __be16 _ports[2], *pptr; |
402 | unsigned int flags; | 399 | unsigned int flags; |
403 | 400 | ||
404 | *ignored = 1; | 401 | *ignored = 1; |
405 | |||
406 | /* | 402 | /* |
407 | * IPv6 frags, only the first hit here. | 403 | * IPv6 frags, only the first hit here. |
408 | */ | 404 | */ |
409 | ip_vs_fill_iph_skb(svc->af, skb, &iph); | 405 | pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); |
410 | pptr = frag_safe_skb_hp(skb, iph.len, sizeof(_ports), _ports, &iph); | ||
411 | if (pptr == NULL) | 406 | if (pptr == NULL) |
412 | return NULL; | 407 | return NULL; |
413 | 408 | ||
@@ -427,7 +422,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
427 | * Do not schedule replies from local real server. | 422 | * Do not schedule replies from local real server. |
428 | */ | 423 | */ |
429 | if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) && | 424 | if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) && |
430 | (cp = pp->conn_in_get(svc->af, skb, &iph, iph.len, 1))) { | 425 | (cp = pp->conn_in_get(svc->af, skb, iph, 1))) { |
431 | IP_VS_DBG_PKT(12, svc->af, pp, skb, 0, | 426 | IP_VS_DBG_PKT(12, svc->af, pp, skb, 0, |
432 | "Not scheduling reply for existing connection"); | 427 | "Not scheduling reply for existing connection"); |
433 | __ip_vs_conn_put(cp); | 428 | __ip_vs_conn_put(cp); |
@@ -438,7 +433,8 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
438 | * Persistent service | 433 | * Persistent service |
439 | */ | 434 | */ |
440 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) | 435 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) |
441 | return ip_vs_sched_persist(svc, skb, pptr[0], pptr[1], ignored); | 436 | return ip_vs_sched_persist(svc, skb, pptr[0], pptr[1], ignored, |
437 | iph); | ||
442 | 438 | ||
443 | *ignored = 0; | 439 | *ignored = 0; |
444 | 440 | ||
@@ -460,7 +456,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
460 | } | 456 | } |
461 | 457 | ||
462 | flags = (svc->flags & IP_VS_SVC_F_ONEPACKET | 458 | flags = (svc->flags & IP_VS_SVC_F_ONEPACKET |
463 | && iph.protocol == IPPROTO_UDP)? | 459 | && iph->protocol == IPPROTO_UDP) ? |
464 | IP_VS_CONN_F_ONE_PACKET : 0; | 460 | IP_VS_CONN_F_ONE_PACKET : 0; |
465 | 461 | ||
466 | /* | 462 | /* |
@@ -469,9 +465,9 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
469 | { | 465 | { |
470 | struct ip_vs_conn_param p; | 466 | struct ip_vs_conn_param p; |
471 | 467 | ||
472 | ip_vs_conn_fill_param(svc->net, svc->af, iph.protocol, | 468 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, |
473 | &iph.saddr, pptr[0], &iph.daddr, pptr[1], | 469 | &iph->saddr, pptr[0], &iph->daddr, |
474 | &p); | 470 | pptr[1], &p); |
475 | cp = ip_vs_conn_new(&p, &dest->addr, | 471 | cp = ip_vs_conn_new(&p, &dest->addr, |
476 | dest->port ? dest->port : pptr[1], | 472 | dest->port ? dest->port : pptr[1], |
477 | flags, dest, skb->mark); | 473 | flags, dest, skb->mark); |
@@ -500,18 +496,16 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
500 | * no destination is available for a new connection. | 496 | * no destination is available for a new connection. |
501 | */ | 497 | */ |
502 | int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | 498 | int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, |
503 | struct ip_vs_proto_data *pd) | 499 | struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph) |
504 | { | 500 | { |
505 | __be16 _ports[2], *pptr; | 501 | __be16 _ports[2], *pptr; |
506 | struct ip_vs_iphdr iph; | ||
507 | #ifdef CONFIG_SYSCTL | 502 | #ifdef CONFIG_SYSCTL |
508 | struct net *net; | 503 | struct net *net; |
509 | struct netns_ipvs *ipvs; | 504 | struct netns_ipvs *ipvs; |
510 | int unicast; | 505 | int unicast; |
511 | #endif | 506 | #endif |
512 | 507 | ||
513 | ip_vs_fill_iph_skb(svc->af, skb, &iph); | 508 | pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); |
514 | pptr = frag_safe_skb_hp(skb, iph.len, sizeof(_ports), _ports, &iph); | ||
515 | if (pptr == NULL) { | 509 | if (pptr == NULL) { |
516 | ip_vs_service_put(svc); | 510 | ip_vs_service_put(svc); |
517 | return NF_DROP; | 511 | return NF_DROP; |
@@ -522,10 +516,10 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
522 | 516 | ||
523 | #ifdef CONFIG_IP_VS_IPV6 | 517 | #ifdef CONFIG_IP_VS_IPV6 |
524 | if (svc->af == AF_INET6) | 518 | if (svc->af == AF_INET6) |
525 | unicast = ipv6_addr_type(&iph.daddr.in6) & IPV6_ADDR_UNICAST; | 519 | unicast = ipv6_addr_type(&iph->daddr.in6) & IPV6_ADDR_UNICAST; |
526 | else | 520 | else |
527 | #endif | 521 | #endif |
528 | unicast = (inet_addr_type(net, iph.daddr.ip) == RTN_UNICAST); | 522 | unicast = (inet_addr_type(net, iph->daddr.ip) == RTN_UNICAST); |
529 | 523 | ||
530 | /* if it is fwmark-based service, the cache_bypass sysctl is up | 524 | /* if it is fwmark-based service, the cache_bypass sysctl is up |
531 | and the destination is a non-local unicast, then create | 525 | and the destination is a non-local unicast, then create |
@@ -535,7 +529,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
535 | int ret; | 529 | int ret; |
536 | struct ip_vs_conn *cp; | 530 | struct ip_vs_conn *cp; |
537 | unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && | 531 | unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && |
538 | iph.protocol == IPPROTO_UDP)? | 532 | iph->protocol == IPPROTO_UDP) ? |
539 | IP_VS_CONN_F_ONE_PACKET : 0; | 533 | IP_VS_CONN_F_ONE_PACKET : 0; |
540 | union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } }; | 534 | union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } }; |
541 | 535 | ||
@@ -545,9 +539,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
545 | IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__); | 539 | IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__); |
546 | { | 540 | { |
547 | struct ip_vs_conn_param p; | 541 | struct ip_vs_conn_param p; |
548 | ip_vs_conn_fill_param(svc->net, svc->af, iph.protocol, | 542 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, |
549 | &iph.saddr, pptr[0], | 543 | &iph->saddr, pptr[0], |
550 | &iph.daddr, pptr[1], &p); | 544 | &iph->daddr, pptr[1], &p); |
551 | cp = ip_vs_conn_new(&p, &daddr, 0, | 545 | cp = ip_vs_conn_new(&p, &daddr, 0, |
552 | IP_VS_CONN_F_BYPASS | flags, | 546 | IP_VS_CONN_F_BYPASS | flags, |
553 | NULL, skb->mark); | 547 | NULL, skb->mark); |
@@ -562,7 +556,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
562 | ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); | 556 | ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); |
563 | 557 | ||
564 | /* transmit the first SYN packet */ | 558 | /* transmit the first SYN packet */ |
565 | ret = cp->packet_xmit(skb, cp, pd->pp); | 559 | ret = cp->packet_xmit(skb, cp, pd->pp, iph); |
566 | /* do not touch skb anymore */ | 560 | /* do not touch skb anymore */ |
567 | 561 | ||
568 | atomic_inc(&cp->in_pkts); | 562 | atomic_inc(&cp->in_pkts); |
@@ -908,7 +902,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related, | |||
908 | ip_vs_fill_ip4hdr(cih, &ciph); | 902 | ip_vs_fill_ip4hdr(cih, &ciph); |
909 | ciph.len += offset; | 903 | ciph.len += offset; |
910 | /* The embedded headers contain source and dest in reverse order */ | 904 | /* The embedded headers contain source and dest in reverse order */ |
911 | cp = pp->conn_out_get(AF_INET, skb, &ciph, offset, 1); | 905 | cp = pp->conn_out_get(AF_INET, skb, &ciph, 1); |
912 | if (!cp) | 906 | if (!cp) |
913 | return NF_ACCEPT; | 907 | return NF_ACCEPT; |
914 | 908 | ||
@@ -919,7 +913,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related, | |||
919 | 913 | ||
920 | #ifdef CONFIG_IP_VS_IPV6 | 914 | #ifdef CONFIG_IP_VS_IPV6 |
921 | static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, | 915 | static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, |
922 | unsigned int hooknum) | 916 | unsigned int hooknum, struct ip_vs_iphdr *ipvsh) |
923 | { | 917 | { |
924 | struct icmp6hdr _icmph, *ic; | 918 | struct icmp6hdr _icmph, *ic; |
925 | struct ipv6hdr _ip6h, *ip6h; /* The ip header contained within ICMP */ | 919 | struct ipv6hdr _ip6h, *ip6h; /* The ip header contained within ICMP */ |
@@ -929,10 +923,6 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, | |||
929 | union nf_inet_addr snet; | 923 | union nf_inet_addr snet; |
930 | unsigned int writable; | 924 | unsigned int writable; |
931 | 925 | ||
932 | struct ip_vs_iphdr ipvsh_stack; | ||
933 | struct ip_vs_iphdr *ipvsh = &ipvsh_stack; | ||
934 | ip_vs_fill_iph_skb(AF_INET6, skb, ipvsh); | ||
935 | |||
936 | *related = 1; | 926 | *related = 1; |
937 | ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh); | 927 | ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh); |
938 | if (ic == NULL) | 928 | if (ic == NULL) |
@@ -976,7 +966,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, | |||
976 | return NF_ACCEPT; | 966 | return NF_ACCEPT; |
977 | 967 | ||
978 | /* The embedded headers contain source and dest in reverse order */ | 968 | /* The embedded headers contain source and dest in reverse order */ |
979 | cp = pp->conn_out_get(AF_INET6, skb, &ciph, ciph.len, 1); | 969 | cp = pp->conn_out_get(AF_INET6, skb, &ciph, 1); |
980 | if (!cp) | 970 | if (!cp) |
981 | return NF_ACCEPT; | 971 | return NF_ACCEPT; |
982 | 972 | ||
@@ -1016,17 +1006,17 @@ static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len) | |||
1016 | */ | 1006 | */ |
1017 | static unsigned int | 1007 | static unsigned int |
1018 | handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 1008 | handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
1019 | struct ip_vs_conn *cp, int ihl) | 1009 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
1020 | { | 1010 | { |
1021 | struct ip_vs_protocol *pp = pd->pp; | 1011 | struct ip_vs_protocol *pp = pd->pp; |
1022 | 1012 | ||
1023 | IP_VS_DBG_PKT(11, af, pp, skb, 0, "Outgoing packet"); | 1013 | IP_VS_DBG_PKT(11, af, pp, skb, 0, "Outgoing packet"); |
1024 | 1014 | ||
1025 | if (!skb_make_writable(skb, ihl)) | 1015 | if (!skb_make_writable(skb, iph->len)) |
1026 | goto drop; | 1016 | goto drop; |
1027 | 1017 | ||
1028 | /* mangle the packet */ | 1018 | /* mangle the packet */ |
1029 | if (pp->snat_handler && !pp->snat_handler(skb, pp, cp)) | 1019 | if (pp->snat_handler && !pp->snat_handler(skb, pp, cp, iph)) |
1030 | goto drop; | 1020 | goto drop; |
1031 | 1021 | ||
1032 | #ifdef CONFIG_IP_VS_IPV6 | 1022 | #ifdef CONFIG_IP_VS_IPV6 |
@@ -1125,7 +1115,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1125 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { | 1115 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { |
1126 | int related; | 1116 | int related; |
1127 | int verdict = ip_vs_out_icmp_v6(skb, &related, | 1117 | int verdict = ip_vs_out_icmp_v6(skb, &related, |
1128 | hooknum); | 1118 | hooknum, &iph); |
1129 | 1119 | ||
1130 | if (related) | 1120 | if (related) |
1131 | return verdict; | 1121 | return verdict; |
@@ -1160,10 +1150,10 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1160 | /* | 1150 | /* |
1161 | * Check if the packet belongs to an existing entry | 1151 | * Check if the packet belongs to an existing entry |
1162 | */ | 1152 | */ |
1163 | cp = pp->conn_out_get(af, skb, &iph, iph.len, 0); | 1153 | cp = pp->conn_out_get(af, skb, &iph, 0); |
1164 | 1154 | ||
1165 | if (likely(cp)) | 1155 | if (likely(cp)) |
1166 | return handle_response(af, skb, pd, cp, iph.len); | 1156 | return handle_response(af, skb, pd, cp, &iph); |
1167 | if (sysctl_nat_icmp_send(net) && | 1157 | if (sysctl_nat_icmp_send(net) && |
1168 | (pp->protocol == IPPROTO_TCP || | 1158 | (pp->protocol == IPPROTO_TCP || |
1169 | pp->protocol == IPPROTO_UDP || | 1159 | pp->protocol == IPPROTO_UDP || |
@@ -1375,7 +1365,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1375 | /* The embedded headers contain source and dest in reverse order. | 1365 | /* The embedded headers contain source and dest in reverse order. |
1376 | * For IPIP this is error for request, not for reply. | 1366 | * For IPIP this is error for request, not for reply. |
1377 | */ | 1367 | */ |
1378 | cp = pp->conn_in_get(AF_INET, skb, &ciph, offset, ipip ? 0 : 1); | 1368 | cp = pp->conn_in_get(AF_INET, skb, &ciph, ipip ? 0 : 1); |
1379 | if (!cp) | 1369 | if (!cp) |
1380 | return NF_ACCEPT; | 1370 | return NF_ACCEPT; |
1381 | 1371 | ||
@@ -1444,7 +1434,7 @@ ignore_ipip: | |||
1444 | ip_vs_in_stats(cp, skb); | 1434 | ip_vs_in_stats(cp, skb); |
1445 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) | 1435 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) |
1446 | offset += 2 * sizeof(__u16); | 1436 | offset += 2 * sizeof(__u16); |
1447 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum); | 1437 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph); |
1448 | 1438 | ||
1449 | out: | 1439 | out: |
1450 | __ip_vs_conn_put(cp); | 1440 | __ip_vs_conn_put(cp); |
@@ -1453,8 +1443,8 @@ out: | |||
1453 | } | 1443 | } |
1454 | 1444 | ||
1455 | #ifdef CONFIG_IP_VS_IPV6 | 1445 | #ifdef CONFIG_IP_VS_IPV6 |
1456 | static int | 1446 | static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, |
1457 | ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | 1447 | unsigned int hooknum, struct ip_vs_iphdr *iph) |
1458 | { | 1448 | { |
1459 | struct net *net = NULL; | 1449 | struct net *net = NULL; |
1460 | struct ipv6hdr _ip6h, *ip6h; | 1450 | struct ipv6hdr _ip6h, *ip6h; |
@@ -1465,10 +1455,6 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1465 | struct ip_vs_proto_data *pd; | 1455 | struct ip_vs_proto_data *pd; |
1466 | unsigned int offs_ciph, writable, verdict; | 1456 | unsigned int offs_ciph, writable, verdict; |
1467 | 1457 | ||
1468 | struct ip_vs_iphdr iph_stack; | ||
1469 | struct ip_vs_iphdr *iph = &iph_stack; | ||
1470 | ip_vs_fill_iph_skb(AF_INET6, skb, iph); | ||
1471 | |||
1472 | *related = 1; | 1458 | *related = 1; |
1473 | 1459 | ||
1474 | ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph); | 1460 | ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph); |
@@ -1525,7 +1511,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1525 | /* The embedded headers contain source and dest in reverse order | 1511 | /* The embedded headers contain source and dest in reverse order |
1526 | * if not from localhost | 1512 | * if not from localhost |
1527 | */ | 1513 | */ |
1528 | cp = pp->conn_in_get(AF_INET6, skb, &ciph, ciph.len, | 1514 | cp = pp->conn_in_get(AF_INET6, skb, &ciph, |
1529 | (hooknum == NF_INET_LOCAL_OUT) ? 0 : 1); | 1515 | (hooknum == NF_INET_LOCAL_OUT) ? 0 : 1); |
1530 | 1516 | ||
1531 | if (!cp) | 1517 | if (!cp) |
@@ -1546,7 +1532,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1546 | IPPROTO_SCTP == ciph.protocol) | 1532 | IPPROTO_SCTP == ciph.protocol) |
1547 | writable += 2 * sizeof(__u16); /* Also mangle ports */ | 1533 | writable += 2 * sizeof(__u16); /* Also mangle ports */ |
1548 | 1534 | ||
1549 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, writable, hooknum); | 1535 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, writable, hooknum, &ciph); |
1550 | 1536 | ||
1551 | __ip_vs_conn_put(cp); | 1537 | __ip_vs_conn_put(cp); |
1552 | 1538 | ||
@@ -1616,7 +1602,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1616 | } | 1602 | } |
1617 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { | 1603 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { |
1618 | int related; | 1604 | int related; |
1619 | int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum); | 1605 | int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum, |
1606 | &iph); | ||
1620 | 1607 | ||
1621 | if (related) | 1608 | if (related) |
1622 | return verdict; | 1609 | return verdict; |
@@ -1639,8 +1626,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1639 | /* | 1626 | /* |
1640 | * Check if the packet belongs to an existing connection entry | 1627 | * Check if the packet belongs to an existing connection entry |
1641 | */ | 1628 | */ |
1642 | cp = pp->conn_in_get(af, skb, &iph, iph.len, 0); | 1629 | cp = pp->conn_in_get(af, skb, &iph, 0); |
1643 | |||
1644 | if (unlikely(!cp) && !iph.fragoffs) { | 1630 | if (unlikely(!cp) && !iph.fragoffs) { |
1645 | /* No (second) fragments need to enter here, as nf_defrag_ipv6 | 1631 | /* No (second) fragments need to enter here, as nf_defrag_ipv6 |
1646 | * replayed fragment zero will already have created the cp | 1632 | * replayed fragment zero will already have created the cp |
@@ -1648,7 +1634,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1648 | int v; | 1634 | int v; |
1649 | 1635 | ||
1650 | /* Schedule and create new connection entry into &cp */ | 1636 | /* Schedule and create new connection entry into &cp */ |
1651 | if (!pp->conn_schedule(af, skb, pd, &v, &cp)) | 1637 | if (!pp->conn_schedule(af, skb, pd, &v, &cp, &iph)) |
1652 | return v; | 1638 | return v; |
1653 | } | 1639 | } |
1654 | 1640 | ||
@@ -1686,7 +1672,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1686 | ip_vs_in_stats(cp, skb); | 1672 | ip_vs_in_stats(cp, skb); |
1687 | ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); | 1673 | ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); |
1688 | if (cp->packet_xmit) | 1674 | if (cp->packet_xmit) |
1689 | ret = cp->packet_xmit(skb, cp, pp); | 1675 | ret = cp->packet_xmit(skb, cp, pp, &iph); |
1690 | /* do not touch skb anymore */ | 1676 | /* do not touch skb anymore */ |
1691 | else { | 1677 | else { |
1692 | IP_VS_DBG_RL("warning: packet_xmit is null"); | 1678 | IP_VS_DBG_RL("warning: packet_xmit is null"); |
@@ -1860,7 +1846,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, | |||
1860 | if (!net_ipvs(net)->enable) | 1846 | if (!net_ipvs(net)->enable) |
1861 | return NF_ACCEPT; | 1847 | return NF_ACCEPT; |
1862 | 1848 | ||
1863 | return ip_vs_in_icmp_v6(skb, &r, hooknum); | 1849 | return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr); |
1864 | } | 1850 | } |
1865 | #endif | 1851 | #endif |
1866 | 1852 | ||
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c index 5b8eb8b12c3..5de3dd312c0 100644 --- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c +++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c | |||
@@ -57,7 +57,7 @@ ah_esp_conn_fill_param_proto(struct net *net, int af, | |||
57 | 57 | ||
58 | static struct ip_vs_conn * | 58 | static struct ip_vs_conn * |
59 | ah_esp_conn_in_get(int af, const struct sk_buff *skb, | 59 | ah_esp_conn_in_get(int af, const struct sk_buff *skb, |
60 | const struct ip_vs_iphdr *iph, unsigned int proto_off, | 60 | const struct ip_vs_iphdr *iph, |
61 | int inverse) | 61 | int inverse) |
62 | { | 62 | { |
63 | struct ip_vs_conn *cp; | 63 | struct ip_vs_conn *cp; |
@@ -85,9 +85,7 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb, | |||
85 | 85 | ||
86 | static struct ip_vs_conn * | 86 | static struct ip_vs_conn * |
87 | ah_esp_conn_out_get(int af, const struct sk_buff *skb, | 87 | ah_esp_conn_out_get(int af, const struct sk_buff *skb, |
88 | const struct ip_vs_iphdr *iph, | 88 | const struct ip_vs_iphdr *iph, int inverse) |
89 | unsigned int proto_off, | ||
90 | int inverse) | ||
91 | { | 89 | { |
92 | struct ip_vs_conn *cp; | 90 | struct ip_vs_conn *cp; |
93 | struct ip_vs_conn_param p; | 91 | struct ip_vs_conn_param p; |
@@ -110,7 +108,8 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb, | |||
110 | 108 | ||
111 | static int | 109 | static int |
112 | ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 110 | ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
113 | int *verdict, struct ip_vs_conn **cpp) | 111 | int *verdict, struct ip_vs_conn **cpp, |
112 | struct ip_vs_iphdr *iph) | ||
114 | { | 113 | { |
115 | /* | 114 | /* |
116 | * AH/ESP is only related traffic. Pass the packet to IP stack. | 115 | * AH/ESP is only related traffic. Pass the packet to IP stack. |
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index b903db60341..746048b13ef 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -10,28 +10,26 @@ | |||
10 | 10 | ||
11 | static int | 11 | static int |
12 | sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 12 | sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
13 | int *verdict, struct ip_vs_conn **cpp) | 13 | int *verdict, struct ip_vs_conn **cpp, |
14 | struct ip_vs_iphdr *iph) | ||
14 | { | 15 | { |
15 | struct net *net; | 16 | struct net *net; |
16 | struct ip_vs_service *svc; | 17 | struct ip_vs_service *svc; |
17 | sctp_chunkhdr_t _schunkh, *sch; | 18 | sctp_chunkhdr_t _schunkh, *sch; |
18 | sctp_sctphdr_t *sh, _sctph; | 19 | sctp_sctphdr_t *sh, _sctph; |
19 | struct ip_vs_iphdr iph; | ||
20 | 20 | ||
21 | ip_vs_fill_iph_skb(af, skb, &iph); | 21 | sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph); |
22 | |||
23 | sh = skb_header_pointer(skb, iph.len, sizeof(_sctph), &_sctph); | ||
24 | if (sh == NULL) | 22 | if (sh == NULL) |
25 | return 0; | 23 | return 0; |
26 | 24 | ||
27 | sch = skb_header_pointer(skb, iph.len + sizeof(sctp_sctphdr_t), | 25 | sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t), |
28 | sizeof(_schunkh), &_schunkh); | 26 | sizeof(_schunkh), &_schunkh); |
29 | if (sch == NULL) | 27 | if (sch == NULL) |
30 | return 0; | 28 | return 0; |
31 | net = skb_net(skb); | 29 | net = skb_net(skb); |
32 | if ((sch->type == SCTP_CID_INIT) && | 30 | if ((sch->type == SCTP_CID_INIT) && |
33 | (svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, | 31 | (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol, |
34 | &iph.daddr, sh->dest))) { | 32 | &iph->daddr, sh->dest))) { |
35 | int ignored; | 33 | int ignored; |
36 | 34 | ||
37 | if (ip_vs_todrop(net_ipvs(net))) { | 35 | if (ip_vs_todrop(net_ipvs(net))) { |
@@ -47,10 +45,10 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
47 | * Let the virtual server select a real server for the | 45 | * Let the virtual server select a real server for the |
48 | * incoming connection, and create a connection entry. | 46 | * incoming connection, and create a connection entry. |
49 | */ | 47 | */ |
50 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored); | 48 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); |
51 | if (!*cpp && ignored <= 0) { | 49 | if (!*cpp && ignored <= 0) { |
52 | if (!ignored) | 50 | if (!ignored) |
53 | *verdict = ip_vs_leave(svc, skb, pd); | 51 | *verdict = ip_vs_leave(svc, skb, pd, iph); |
54 | else { | 52 | else { |
55 | ip_vs_service_put(svc); | 53 | ip_vs_service_put(svc); |
56 | *verdict = NF_DROP; | 54 | *verdict = NF_DROP; |
@@ -64,20 +62,16 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
64 | } | 62 | } |
65 | 63 | ||
66 | static int | 64 | static int |
67 | sctp_snat_handler(struct sk_buff *skb, | 65 | sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
68 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 66 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
69 | { | 67 | { |
70 | sctp_sctphdr_t *sctph; | 68 | sctp_sctphdr_t *sctph; |
71 | unsigned int sctphoff; | 69 | unsigned int sctphoff = iph->len; |
72 | struct sk_buff *iter; | 70 | struct sk_buff *iter; |
73 | __be32 crc32; | 71 | __be32 crc32; |
74 | 72 | ||
75 | struct ip_vs_iphdr iph; | ||
76 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
77 | sctphoff = iph.len; | ||
78 | |||
79 | #ifdef CONFIG_IP_VS_IPV6 | 73 | #ifdef CONFIG_IP_VS_IPV6 |
80 | if (cp->af == AF_INET6 && iph.fragoffs) | 74 | if (cp->af == AF_INET6 && iph->fragoffs) |
81 | return 1; | 75 | return 1; |
82 | #endif | 76 | #endif |
83 | 77 | ||
@@ -110,20 +104,16 @@ sctp_snat_handler(struct sk_buff *skb, | |||
110 | } | 104 | } |
111 | 105 | ||
112 | static int | 106 | static int |
113 | sctp_dnat_handler(struct sk_buff *skb, | 107 | sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
114 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 108 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
115 | { | 109 | { |
116 | sctp_sctphdr_t *sctph; | 110 | sctp_sctphdr_t *sctph; |
117 | unsigned int sctphoff; | 111 | unsigned int sctphoff = iph->len; |
118 | struct sk_buff *iter; | 112 | struct sk_buff *iter; |
119 | __be32 crc32; | 113 | __be32 crc32; |
120 | 114 | ||
121 | struct ip_vs_iphdr iph; | ||
122 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
123 | sctphoff = iph.len; | ||
124 | |||
125 | #ifdef CONFIG_IP_VS_IPV6 | 115 | #ifdef CONFIG_IP_VS_IPV6 |
126 | if (cp->af == AF_INET6 && iph.fragoffs) | 116 | if (cp->af == AF_INET6 && iph->fragoffs) |
127 | return 1; | 117 | return 1; |
128 | #endif | 118 | #endif |
129 | 119 | ||
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 8a96069c002..9af653a7582 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c | |||
@@ -33,16 +33,14 @@ | |||
33 | 33 | ||
34 | static int | 34 | static int |
35 | tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 35 | tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
36 | int *verdict, struct ip_vs_conn **cpp) | 36 | int *verdict, struct ip_vs_conn **cpp, |
37 | struct ip_vs_iphdr *iph) | ||
37 | { | 38 | { |
38 | struct net *net; | 39 | struct net *net; |
39 | struct ip_vs_service *svc; | 40 | struct ip_vs_service *svc; |
40 | struct tcphdr _tcph, *th; | 41 | struct tcphdr _tcph, *th; |
41 | struct ip_vs_iphdr iph; | ||
42 | 42 | ||
43 | ip_vs_fill_iph_skb(af, skb, &iph); | 43 | th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph); |
44 | |||
45 | th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph); | ||
46 | if (th == NULL) { | 44 | if (th == NULL) { |
47 | *verdict = NF_DROP; | 45 | *verdict = NF_DROP; |
48 | return 0; | 46 | return 0; |
@@ -50,8 +48,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
50 | net = skb_net(skb); | 48 | net = skb_net(skb); |
51 | /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */ | 49 | /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */ |
52 | if (th->syn && | 50 | if (th->syn && |
53 | (svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, | 51 | (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol, |
54 | &iph.daddr, th->dest))) { | 52 | &iph->daddr, th->dest))) { |
55 | int ignored; | 53 | int ignored; |
56 | 54 | ||
57 | if (ip_vs_todrop(net_ipvs(net))) { | 55 | if (ip_vs_todrop(net_ipvs(net))) { |
@@ -68,10 +66,10 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
68 | * Let the virtual server select a real server for the | 66 | * Let the virtual server select a real server for the |
69 | * incoming connection, and create a connection entry. | 67 | * incoming connection, and create a connection entry. |
70 | */ | 68 | */ |
71 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored); | 69 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); |
72 | if (!*cpp && ignored <= 0) { | 70 | if (!*cpp && ignored <= 0) { |
73 | if (!ignored) | 71 | if (!ignored) |
74 | *verdict = ip_vs_leave(svc, skb, pd); | 72 | *verdict = ip_vs_leave(svc, skb, pd, iph); |
75 | else { | 73 | else { |
76 | ip_vs_service_put(svc); | 74 | ip_vs_service_put(svc); |
77 | *verdict = NF_DROP; | 75 | *verdict = NF_DROP; |
@@ -128,20 +126,16 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph, | |||
128 | 126 | ||
129 | 127 | ||
130 | static int | 128 | static int |
131 | tcp_snat_handler(struct sk_buff *skb, | 129 | tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
132 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 130 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
133 | { | 131 | { |
134 | struct tcphdr *tcph; | 132 | struct tcphdr *tcph; |
135 | unsigned int tcphoff; | 133 | unsigned int tcphoff = iph->len; |
136 | int oldlen; | 134 | int oldlen; |
137 | int payload_csum = 0; | 135 | int payload_csum = 0; |
138 | 136 | ||
139 | struct ip_vs_iphdr iph; | ||
140 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
141 | tcphoff = iph.len; | ||
142 | |||
143 | #ifdef CONFIG_IP_VS_IPV6 | 137 | #ifdef CONFIG_IP_VS_IPV6 |
144 | if (cp->af == AF_INET6 && iph.fragoffs) | 138 | if (cp->af == AF_INET6 && iph->fragoffs) |
145 | return 1; | 139 | return 1; |
146 | #endif | 140 | #endif |
147 | oldlen = skb->len - tcphoff; | 141 | oldlen = skb->len - tcphoff; |
@@ -210,20 +204,16 @@ tcp_snat_handler(struct sk_buff *skb, | |||
210 | 204 | ||
211 | 205 | ||
212 | static int | 206 | static int |
213 | tcp_dnat_handler(struct sk_buff *skb, | 207 | tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
214 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 208 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
215 | { | 209 | { |
216 | struct tcphdr *tcph; | 210 | struct tcphdr *tcph; |
217 | unsigned int tcphoff; | 211 | unsigned int tcphoff = iph->len; |
218 | int oldlen; | 212 | int oldlen; |
219 | int payload_csum = 0; | 213 | int payload_csum = 0; |
220 | 214 | ||
221 | struct ip_vs_iphdr iph; | ||
222 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
223 | tcphoff = iph.len; | ||
224 | |||
225 | #ifdef CONFIG_IP_VS_IPV6 | 215 | #ifdef CONFIG_IP_VS_IPV6 |
226 | if (cp->af == AF_INET6 && iph.fragoffs) | 216 | if (cp->af == AF_INET6 && iph->fragoffs) |
227 | return 1; | 217 | return 1; |
228 | #endif | 218 | #endif |
229 | oldlen = skb->len - tcphoff; | 219 | oldlen = skb->len - tcphoff; |
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index d6f4eeec8b7..503a842c90d 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c | |||
@@ -30,23 +30,22 @@ | |||
30 | 30 | ||
31 | static int | 31 | static int |
32 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | 32 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, |
33 | int *verdict, struct ip_vs_conn **cpp) | 33 | int *verdict, struct ip_vs_conn **cpp, |
34 | struct ip_vs_iphdr *iph) | ||
34 | { | 35 | { |
35 | struct net *net; | 36 | struct net *net; |
36 | struct ip_vs_service *svc; | 37 | struct ip_vs_service *svc; |
37 | struct udphdr _udph, *uh; | 38 | struct udphdr _udph, *uh; |
38 | struct ip_vs_iphdr iph; | ||
39 | 39 | ||
40 | ip_vs_fill_iph_skb(af, skb, &iph); | 40 | /* IPv6 fragments, only first fragment will hit this */ |
41 | 41 | uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph); | |
42 | uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph); | ||
43 | if (uh == NULL) { | 42 | if (uh == NULL) { |
44 | *verdict = NF_DROP; | 43 | *verdict = NF_DROP; |
45 | return 0; | 44 | return 0; |
46 | } | 45 | } |
47 | net = skb_net(skb); | 46 | net = skb_net(skb); |
48 | svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, | 47 | svc = ip_vs_service_get(net, af, skb->mark, iph->protocol, |
49 | &iph.daddr, uh->dest); | 48 | &iph->daddr, uh->dest); |
50 | if (svc) { | 49 | if (svc) { |
51 | int ignored; | 50 | int ignored; |
52 | 51 | ||
@@ -64,10 +63,10 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
64 | * Let the virtual server select a real server for the | 63 | * Let the virtual server select a real server for the |
65 | * incoming connection, and create a connection entry. | 64 | * incoming connection, and create a connection entry. |
66 | */ | 65 | */ |
67 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored); | 66 | *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); |
68 | if (!*cpp && ignored <= 0) { | 67 | if (!*cpp && ignored <= 0) { |
69 | if (!ignored) | 68 | if (!ignored) |
70 | *verdict = ip_vs_leave(svc, skb, pd); | 69 | *verdict = ip_vs_leave(svc, skb, pd, iph); |
71 | else { | 70 | else { |
72 | ip_vs_service_put(svc); | 71 | ip_vs_service_put(svc); |
73 | *verdict = NF_DROP; | 72 | *verdict = NF_DROP; |
@@ -125,20 +124,16 @@ udp_partial_csum_update(int af, struct udphdr *uhdr, | |||
125 | 124 | ||
126 | 125 | ||
127 | static int | 126 | static int |
128 | udp_snat_handler(struct sk_buff *skb, | 127 | udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
129 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 128 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
130 | { | 129 | { |
131 | struct udphdr *udph; | 130 | struct udphdr *udph; |
132 | unsigned int udphoff; | 131 | unsigned int udphoff = iph->len; |
133 | int oldlen; | 132 | int oldlen; |
134 | int payload_csum = 0; | 133 | int payload_csum = 0; |
135 | 134 | ||
136 | struct ip_vs_iphdr iph; | ||
137 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
138 | udphoff = iph.len; | ||
139 | |||
140 | #ifdef CONFIG_IP_VS_IPV6 | 135 | #ifdef CONFIG_IP_VS_IPV6 |
141 | if (cp->af == AF_INET6 && iph.fragoffs) | 136 | if (cp->af == AF_INET6 && iph->fragoffs) |
142 | return 1; | 137 | return 1; |
143 | #endif | 138 | #endif |
144 | oldlen = skb->len - udphoff; | 139 | oldlen = skb->len - udphoff; |
@@ -212,20 +207,16 @@ udp_snat_handler(struct sk_buff *skb, | |||
212 | 207 | ||
213 | 208 | ||
214 | static int | 209 | static int |
215 | udp_dnat_handler(struct sk_buff *skb, | 210 | udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
216 | struct ip_vs_protocol *pp, struct ip_vs_conn *cp) | 211 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
217 | { | 212 | { |
218 | struct udphdr *udph; | 213 | struct udphdr *udph; |
219 | unsigned int udphoff; | 214 | unsigned int udphoff = iph->len; |
220 | int oldlen; | 215 | int oldlen; |
221 | int payload_csum = 0; | 216 | int payload_csum = 0; |
222 | 217 | ||
223 | struct ip_vs_iphdr iph; | ||
224 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
225 | udphoff = iph.len; | ||
226 | |||
227 | #ifdef CONFIG_IP_VS_IPV6 | 218 | #ifdef CONFIG_IP_VS_IPV6 |
228 | if (cp->af == AF_INET6 && iph.fragoffs) | 219 | if (cp->af == AF_INET6 && iph->fragoffs) |
229 | return 1; | 220 | return 1; |
230 | #endif | 221 | #endif |
231 | oldlen = skb->len - udphoff; | 222 | oldlen = skb->len - udphoff; |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index a8b75fc8e6a..90122eb0b04 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -424,7 +424,7 @@ do { \ | |||
424 | */ | 424 | */ |
425 | int | 425 | int |
426 | ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 426 | ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
427 | struct ip_vs_protocol *pp) | 427 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
428 | { | 428 | { |
429 | /* we do not touch skb and do not need pskb ptr */ | 429 | /* we do not touch skb and do not need pskb ptr */ |
430 | IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1); | 430 | IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1); |
@@ -438,7 +438,7 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
438 | */ | 438 | */ |
439 | int | 439 | int |
440 | ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 440 | ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
441 | struct ip_vs_protocol *pp) | 441 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
442 | { | 442 | { |
443 | struct rtable *rt; /* Route to the other host */ | 443 | struct rtable *rt; /* Route to the other host */ |
444 | struct iphdr *iph = ip_hdr(skb); | 444 | struct iphdr *iph = ip_hdr(skb); |
@@ -493,16 +493,14 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
493 | #ifdef CONFIG_IP_VS_IPV6 | 493 | #ifdef CONFIG_IP_VS_IPV6 |
494 | int | 494 | int |
495 | ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 495 | ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
496 | struct ip_vs_protocol *pp) | 496 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph) |
497 | { | 497 | { |
498 | struct rt6_info *rt; /* Route to the other host */ | 498 | struct rt6_info *rt; /* Route to the other host */ |
499 | struct ip_vs_iphdr iph; | ||
500 | int mtu; | 499 | int mtu; |
501 | 500 | ||
502 | EnterFunction(10); | 501 | EnterFunction(10); |
503 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
504 | 502 | ||
505 | rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph.daddr.in6, NULL, 0, | 503 | rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr.in6, NULL, 0, |
506 | IP_VS_RT_MODE_NON_LOCAL); | 504 | IP_VS_RT_MODE_NON_LOCAL); |
507 | if (!rt) | 505 | if (!rt) |
508 | goto tx_error_icmp; | 506 | goto tx_error_icmp; |
@@ -516,7 +514,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
516 | skb->dev = net->loopback_dev; | 514 | skb->dev = net->loopback_dev; |
517 | } | 515 | } |
518 | /* only send ICMP too big on first fragment */ | 516 | /* only send ICMP too big on first fragment */ |
519 | if (!iph.fragoffs) | 517 | if (!iph->fragoffs) |
520 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 518 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
521 | dst_release(&rt->dst); | 519 | dst_release(&rt->dst); |
522 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 520 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
@@ -560,7 +558,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
560 | */ | 558 | */ |
561 | int | 559 | int |
562 | ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 560 | ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
563 | struct ip_vs_protocol *pp) | 561 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
564 | { | 562 | { |
565 | struct rtable *rt; /* Route to the other host */ | 563 | struct rtable *rt; /* Route to the other host */ |
566 | int mtu; | 564 | int mtu; |
@@ -630,7 +628,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
630 | goto tx_error_put; | 628 | goto tx_error_put; |
631 | 629 | ||
632 | /* mangle the packet */ | 630 | /* mangle the packet */ |
633 | if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) | 631 | if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, ipvsh)) |
634 | goto tx_error_put; | 632 | goto tx_error_put; |
635 | ip_hdr(skb)->daddr = cp->daddr.ip; | 633 | ip_hdr(skb)->daddr = cp->daddr.ip; |
636 | ip_send_check(ip_hdr(skb)); | 634 | ip_send_check(ip_hdr(skb)); |
@@ -678,20 +676,18 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
678 | #ifdef CONFIG_IP_VS_IPV6 | 676 | #ifdef CONFIG_IP_VS_IPV6 |
679 | int | 677 | int |
680 | ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 678 | ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
681 | struct ip_vs_protocol *pp) | 679 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph) |
682 | { | 680 | { |
683 | struct rt6_info *rt; /* Route to the other host */ | 681 | struct rt6_info *rt; /* Route to the other host */ |
684 | int mtu; | 682 | int mtu; |
685 | int local; | 683 | int local; |
686 | struct ip_vs_iphdr iph; | ||
687 | 684 | ||
688 | EnterFunction(10); | 685 | EnterFunction(10); |
689 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
690 | 686 | ||
691 | /* check if it is a connection of no-client-port */ | 687 | /* check if it is a connection of no-client-port */ |
692 | if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph.fragoffs)) { | 688 | if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph->fragoffs)) { |
693 | __be16 _pt, *p; | 689 | __be16 _pt, *p; |
694 | p = skb_header_pointer(skb, iph.len, sizeof(_pt), &_pt); | 690 | p = skb_header_pointer(skb, iph->len, sizeof(_pt), &_pt); |
695 | if (p == NULL) | 691 | if (p == NULL) |
696 | goto tx_error; | 692 | goto tx_error; |
697 | ip_vs_conn_fill_cport(cp, *p); | 693 | ip_vs_conn_fill_cport(cp, *p); |
@@ -740,7 +736,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
740 | skb->dev = net->loopback_dev; | 736 | skb->dev = net->loopback_dev; |
741 | } | 737 | } |
742 | /* only send ICMP too big on first fragment */ | 738 | /* only send ICMP too big on first fragment */ |
743 | if (!iph.fragoffs) | 739 | if (!iph->fragoffs) |
744 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 740 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
745 | IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0, | 741 | IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0, |
746 | "ip_vs_nat_xmit_v6(): frag needed for"); | 742 | "ip_vs_nat_xmit_v6(): frag needed for"); |
@@ -755,7 +751,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
755 | goto tx_error_put; | 751 | goto tx_error_put; |
756 | 752 | ||
757 | /* mangle the packet */ | 753 | /* mangle the packet */ |
758 | if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) | 754 | if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, iph)) |
759 | goto tx_error; | 755 | goto tx_error; |
760 | ipv6_hdr(skb)->daddr = cp->daddr.in6; | 756 | ipv6_hdr(skb)->daddr = cp->daddr.in6; |
761 | 757 | ||
@@ -816,7 +812,7 @@ tx_error_put: | |||
816 | */ | 812 | */ |
817 | int | 813 | int |
818 | ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 814 | ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
819 | struct ip_vs_protocol *pp) | 815 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
820 | { | 816 | { |
821 | struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); | 817 | struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); |
822 | struct rtable *rt; /* Route to the other host */ | 818 | struct rtable *rt; /* Route to the other host */ |
@@ -936,7 +932,7 @@ tx_error_put: | |||
936 | #ifdef CONFIG_IP_VS_IPV6 | 932 | #ifdef CONFIG_IP_VS_IPV6 |
937 | int | 933 | int |
938 | ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 934 | ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
939 | struct ip_vs_protocol *pp) | 935 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
940 | { | 936 | { |
941 | struct rt6_info *rt; /* Route to the other host */ | 937 | struct rt6_info *rt; /* Route to the other host */ |
942 | struct in6_addr saddr; /* Source for tunnel */ | 938 | struct in6_addr saddr; /* Source for tunnel */ |
@@ -946,10 +942,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
946 | unsigned int max_headroom; /* The extra header space needed */ | 942 | unsigned int max_headroom; /* The extra header space needed */ |
947 | int mtu; | 943 | int mtu; |
948 | int ret; | 944 | int ret; |
949 | struct ip_vs_iphdr ipvsh; | ||
950 | 945 | ||
951 | EnterFunction(10); | 946 | EnterFunction(10); |
952 | ip_vs_fill_iph_skb(cp->af, skb, &ipvsh); | ||
953 | 947 | ||
954 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, | 948 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, |
955 | &saddr, 1, (IP_VS_RT_MODE_LOCAL | | 949 | &saddr, 1, (IP_VS_RT_MODE_LOCAL | |
@@ -979,7 +973,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
979 | skb->dev = net->loopback_dev; | 973 | skb->dev = net->loopback_dev; |
980 | } | 974 | } |
981 | /* only send ICMP too big on first fragment */ | 975 | /* only send ICMP too big on first fragment */ |
982 | if (!ipvsh.fragoffs) | 976 | if (!ipvsh->fragoffs) |
983 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 977 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
984 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 978 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
985 | goto tx_error_put; | 979 | goto tx_error_put; |
@@ -1061,7 +1055,7 @@ tx_error_put: | |||
1061 | */ | 1055 | */ |
1062 | int | 1056 | int |
1063 | ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 1057 | ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
1064 | struct ip_vs_protocol *pp) | 1058 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) |
1065 | { | 1059 | { |
1066 | struct rtable *rt; /* Route to the other host */ | 1060 | struct rtable *rt; /* Route to the other host */ |
1067 | struct iphdr *iph = ip_hdr(skb); | 1061 | struct iphdr *iph = ip_hdr(skb); |
@@ -1122,14 +1116,12 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1122 | #ifdef CONFIG_IP_VS_IPV6 | 1116 | #ifdef CONFIG_IP_VS_IPV6 |
1123 | int | 1117 | int |
1124 | ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 1118 | ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
1125 | struct ip_vs_protocol *pp) | 1119 | struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph) |
1126 | { | 1120 | { |
1127 | struct rt6_info *rt; /* Route to the other host */ | 1121 | struct rt6_info *rt; /* Route to the other host */ |
1128 | int mtu; | 1122 | int mtu; |
1129 | struct ip_vs_iphdr iph; | ||
1130 | 1123 | ||
1131 | EnterFunction(10); | 1124 | EnterFunction(10); |
1132 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
1133 | 1125 | ||
1134 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1126 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, |
1135 | 0, (IP_VS_RT_MODE_LOCAL | | 1127 | 0, (IP_VS_RT_MODE_LOCAL | |
@@ -1149,7 +1141,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1149 | skb->dev = net->loopback_dev; | 1141 | skb->dev = net->loopback_dev; |
1150 | } | 1142 | } |
1151 | /* only send ICMP too big on first fragment */ | 1143 | /* only send ICMP too big on first fragment */ |
1152 | if (!iph.fragoffs) | 1144 | if (!iph->fragoffs) |
1153 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 1145 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1154 | dst_release(&rt->dst); | 1146 | dst_release(&rt->dst); |
1155 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 1147 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
@@ -1194,7 +1186,8 @@ tx_error: | |||
1194 | */ | 1186 | */ |
1195 | int | 1187 | int |
1196 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 1188 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
1197 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) | 1189 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum, |
1190 | struct ip_vs_iphdr *iph) | ||
1198 | { | 1191 | { |
1199 | struct rtable *rt; /* Route to the other host */ | 1192 | struct rtable *rt; /* Route to the other host */ |
1200 | int mtu; | 1193 | int mtu; |
@@ -1209,7 +1202,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1209 | translate address/port back */ | 1202 | translate address/port back */ |
1210 | if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { | 1203 | if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { |
1211 | if (cp->packet_xmit) | 1204 | if (cp->packet_xmit) |
1212 | rc = cp->packet_xmit(skb, cp, pp); | 1205 | rc = cp->packet_xmit(skb, cp, pp, iph); |
1213 | else | 1206 | else |
1214 | rc = NF_ACCEPT; | 1207 | rc = NF_ACCEPT; |
1215 | /* do not touch skb anymore */ | 1208 | /* do not touch skb anymore */ |
@@ -1315,24 +1308,23 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1315 | #ifdef CONFIG_IP_VS_IPV6 | 1308 | #ifdef CONFIG_IP_VS_IPV6 |
1316 | int | 1309 | int |
1317 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 1310 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
1318 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) | 1311 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum, |
1312 | struct ip_vs_iphdr *iph) | ||
1319 | { | 1313 | { |
1320 | struct rt6_info *rt; /* Route to the other host */ | 1314 | struct rt6_info *rt; /* Route to the other host */ |
1321 | int mtu; | 1315 | int mtu; |
1322 | int rc; | 1316 | int rc; |
1323 | int local; | 1317 | int local; |
1324 | int rt_mode; | 1318 | int rt_mode; |
1325 | struct ip_vs_iphdr iph; | ||
1326 | 1319 | ||
1327 | EnterFunction(10); | 1320 | EnterFunction(10); |
1328 | ip_vs_fill_iph_skb(cp->af, skb, &iph); | ||
1329 | 1321 | ||
1330 | /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be | 1322 | /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be |
1331 | forwarded directly here, because there is no need to | 1323 | forwarded directly here, because there is no need to |
1332 | translate address/port back */ | 1324 | translate address/port back */ |
1333 | if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { | 1325 | if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { |
1334 | if (cp->packet_xmit) | 1326 | if (cp->packet_xmit) |
1335 | rc = cp->packet_xmit(skb, cp, pp); | 1327 | rc = cp->packet_xmit(skb, cp, pp, iph); |
1336 | else | 1328 | else |
1337 | rc = NF_ACCEPT; | 1329 | rc = NF_ACCEPT; |
1338 | /* do not touch skb anymore */ | 1330 | /* do not touch skb anymore */ |
@@ -1389,7 +1381,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1389 | skb->dev = net->loopback_dev; | 1381 | skb->dev = net->loopback_dev; |
1390 | } | 1382 | } |
1391 | /* only send ICMP too big on first fragment */ | 1383 | /* only send ICMP too big on first fragment */ |
1392 | if (!iph.fragoffs) | 1384 | if (!iph->fragoffs) |
1393 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 1385 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1394 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); | 1386 | IP_VS_DBG_RL("%s(): frag needed\n", __func__); |
1395 | goto tx_error_put; | 1387 | goto tx_error_put; |
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c index 3f9b8cde245..8d47c3780fd 100644 --- a/net/netfilter/xt_ipvs.c +++ b/net/netfilter/xt_ipvs.c | |||
@@ -85,7 +85,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
85 | /* | 85 | /* |
86 | * Check if the packet belongs to an existing entry | 86 | * Check if the packet belongs to an existing entry |
87 | */ | 87 | */ |
88 | cp = pp->conn_out_get(family, skb, &iph, iph.len, 1 /* inverse */); | 88 | cp = pp->conn_out_get(family, skb, &iph, 1 /* inverse */); |
89 | if (unlikely(cp == NULL)) { | 89 | if (unlikely(cp == NULL)) { |
90 | match = false; | 90 | match = false; |
91 | goto out; | 91 | goto out; |