aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2012-09-26 08:07:17 -0400
committerSimon Horman <horms@verge.net.au>2012-09-27 22:34:33 -0400
commitd4383f04d145cce8b855c463f40020639ef83ea0 (patch)
tree7807b2b3114fc25c03eb3d3741f9b6d1b17aedfe /net/netfilter
parent2f74713d1436b7d2d0506ba1bc5f10915a73bbec (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.c15
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c116
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_ah_esp.c9
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c42
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c40
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c41
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c58
-rw-r--r--net/netfilter/xt_ipvs.c2
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)
308static int 308static int
309ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, 309ip_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
330struct ip_vs_conn * 329struct ip_vs_conn *
331ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, 330ip_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
433struct ip_vs_conn * 431struct ip_vs_conn *
434ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, 432ip_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 */
223static struct ip_vs_conn * 223static struct ip_vs_conn *
224ip_vs_sched_persist(struct ip_vs_service *svc, 224ip_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, &param); 349 src_port, &iph->daddr, dst_port, &param);
353 350
354 cp = ip_vs_conn_new(&param, &dest->addr, dport, flags, dest, skb->mark); 351 cp = ip_vs_conn_new(&param, &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 */
393struct ip_vs_conn * 390struct ip_vs_conn *
394ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, 391ip_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 */
502int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, 498int 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
921static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, 915static 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 */
1017static unsigned int 1007static unsigned int
1018handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, 1008handle_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
1449out: 1439out:
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
1456static int 1446static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related,
1457ip_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
58static struct ip_vs_conn * 58static struct ip_vs_conn *
59ah_esp_conn_in_get(int af, const struct sk_buff *skb, 59ah_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
86static struct ip_vs_conn * 86static struct ip_vs_conn *
87ah_esp_conn_out_get(int af, const struct sk_buff *skb, 87ah_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
111static int 109static int
112ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, 110ah_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
11static int 11static int
12sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, 12sctp_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
66static int 64static int
67sctp_snat_handler(struct sk_buff *skb, 65sctp_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
112static int 106static int
113sctp_dnat_handler(struct sk_buff *skb, 107sctp_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
34static int 34static int
35tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, 35tcp_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
130static int 128static int
131tcp_snat_handler(struct sk_buff *skb, 129tcp_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
212static int 206static int
213tcp_dnat_handler(struct sk_buff *skb, 207tcp_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
31static int 31static int
32udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, 32udp_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
127static int 126static int
128udp_snat_handler(struct sk_buff *skb, 127udp_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
214static int 209static int
215udp_dnat_handler(struct sk_buff *skb, 210udp_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 */
425int 425int
426ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 426ip_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 */
439int 439int
440ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 440ip_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
494int 494int
495ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, 495ip_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 */
561int 559int
562ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 560ip_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
679int 677int
680ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, 678ip_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 */
817int 813int
818ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 814ip_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
937int 933int
938ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, 934ip_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 */
1062int 1056int
1063ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 1057ip_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
1123int 1117int
1124ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, 1118ip_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 */
1195int 1187int
1196ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, 1188ip_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
1316int 1309int
1317ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, 1310ip_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;