aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulius Volz <juliusv@google.com>2008-09-02 09:55:40 -0400
committerSimon Horman <horms@verge.net.au>2008-09-04 21:17:06 -0400
commit51ef348b14183789e4cb3444d05ce83b1b69d8fb (patch)
treee14e54ce262073b63a3343c764b8174b1041b577 /net
parentb14198f6c1bea1687d20723db35d8effecd9d899 (diff)
IPVS: Add 'af' args to protocol handler functions
Add 'af' arguments to conn_schedule(), conn_in_get(), conn_out_get() and csum_check() function pointers in struct ip_vs_protocol. Extend the respective functions for TCP, UDP, AH and ESP and adjust the callers. The changes in the callers need to be somewhat extensive, since they now need to pass a filled out struct ip_vs_iphdr * to the modified functions instead of a struct iphdr *. Signed-off-by: Julius Volz <juliusv@google.com> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c64
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_ah_esp.c56
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c79
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c81
4 files changed, 162 insertions, 118 deletions
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 4a54f33b60d4..34aaa1480d90 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -572,6 +572,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
572 struct iphdr *iph; 572 struct iphdr *iph;
573 struct icmphdr _icmph, *ic; 573 struct icmphdr _icmph, *ic;
574 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ 574 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
575 struct ip_vs_iphdr ciph;
575 struct ip_vs_conn *cp; 576 struct ip_vs_conn *cp;
576 struct ip_vs_protocol *pp; 577 struct ip_vs_protocol *pp;
577 unsigned int offset, ihl, verdict; 578 unsigned int offset, ihl, verdict;
@@ -627,8 +628,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
627 628
628 offset += cih->ihl * 4; 629 offset += cih->ihl * 4;
629 630
631 ip_vs_fill_iphdr(AF_INET, cih, &ciph);
630 /* The embedded headers contain source and dest in reverse order */ 632 /* The embedded headers contain source and dest in reverse order */
631 cp = pp->conn_out_get(skb, pp, cih, offset, 1); 633 cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
632 if (!cp) 634 if (!cp)
633 return NF_ACCEPT; 635 return NF_ACCEPT;
634 636
@@ -686,43 +688,41 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
686 const struct net_device *in, const struct net_device *out, 688 const struct net_device *in, const struct net_device *out,
687 int (*okfn)(struct sk_buff *)) 689 int (*okfn)(struct sk_buff *))
688{ 690{
689 struct iphdr *iph; 691 struct ip_vs_iphdr iph;
690 struct ip_vs_protocol *pp; 692 struct ip_vs_protocol *pp;
691 struct ip_vs_conn *cp; 693 struct ip_vs_conn *cp;
692 int ihl;
693 694
694 EnterFunction(11); 695 EnterFunction(11);
695 696
696 if (skb->ipvs_property) 697 if (skb->ipvs_property)
697 return NF_ACCEPT; 698 return NF_ACCEPT;
698 699
699 iph = ip_hdr(skb); 700 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
700 if (unlikely(iph->protocol == IPPROTO_ICMP)) { 701 if (unlikely(iph.protocol == IPPROTO_ICMP)) {
701 int related, verdict = ip_vs_out_icmp(skb, &related); 702 int related, verdict = ip_vs_out_icmp(skb, &related);
702 703
703 if (related) 704 if (related)
704 return verdict; 705 return verdict;
705 iph = ip_hdr(skb); 706 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
706 } 707 }
707 708
708 pp = ip_vs_proto_get(iph->protocol); 709 pp = ip_vs_proto_get(iph.protocol);
709 if (unlikely(!pp)) 710 if (unlikely(!pp))
710 return NF_ACCEPT; 711 return NF_ACCEPT;
711 712
712 /* reassemble IP fragments */ 713 /* reassemble IP fragments */
713 if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) && 714 if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
714 !pp->dont_defrag)) { 715 !pp->dont_defrag)) {
715 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) 716 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
716 return NF_STOLEN; 717 return NF_STOLEN;
717 iph = ip_hdr(skb);
718 }
719 718
720 ihl = iph->ihl << 2; 719 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
720 }
721 721
722 /* 722 /*
723 * Check if the packet belongs to an existing entry 723 * Check if the packet belongs to an existing entry
724 */ 724 */
725 cp = pp->conn_out_get(skb, pp, iph, ihl, 0); 725 cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0);
726 726
727 if (unlikely(!cp)) { 727 if (unlikely(!cp)) {
728 if (sysctl_ip_vs_nat_icmp_send && 728 if (sysctl_ip_vs_nat_icmp_send &&
@@ -730,18 +730,18 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
730 pp->protocol == IPPROTO_UDP)) { 730 pp->protocol == IPPROTO_UDP)) {
731 __be16 _ports[2], *pptr; 731 __be16 _ports[2], *pptr;
732 732
733 pptr = skb_header_pointer(skb, ihl, 733 pptr = skb_header_pointer(skb, iph.len,
734 sizeof(_ports), _ports); 734 sizeof(_ports), _ports);
735 if (pptr == NULL) 735 if (pptr == NULL)
736 return NF_ACCEPT; /* Not for me */ 736 return NF_ACCEPT; /* Not for me */
737 if (ip_vs_lookup_real_service(iph->protocol, 737 if (ip_vs_lookup_real_service(iph.protocol,
738 iph->saddr, pptr[0])) { 738 iph.saddr.ip, pptr[0])) {
739 /* 739 /*
740 * Notify the real server: there is no 740 * Notify the real server: there is no
741 * existing entry if it is not RST 741 * existing entry if it is not RST
742 * packet or not TCP packet. 742 * packet or not TCP packet.
743 */ 743 */
744 if (iph->protocol != IPPROTO_TCP 744 if (iph.protocol != IPPROTO_TCP
745 || !is_tcp_reset(skb)) { 745 || !is_tcp_reset(skb)) {
746 icmp_send(skb,ICMP_DEST_UNREACH, 746 icmp_send(skb,ICMP_DEST_UNREACH,
747 ICMP_PORT_UNREACH, 0); 747 ICMP_PORT_UNREACH, 0);
@@ -756,7 +756,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
756 756
757 IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); 757 IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
758 758
759 if (!skb_make_writable(skb, ihl)) 759 if (!skb_make_writable(skb, iph.len))
760 goto drop; 760 goto drop;
761 761
762 /* mangle the packet */ 762 /* mangle the packet */
@@ -804,6 +804,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
804 struct iphdr *iph; 804 struct iphdr *iph;
805 struct icmphdr _icmph, *ic; 805 struct icmphdr _icmph, *ic;
806 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ 806 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
807 struct ip_vs_iphdr ciph;
807 struct ip_vs_conn *cp; 808 struct ip_vs_conn *cp;
808 struct ip_vs_protocol *pp; 809 struct ip_vs_protocol *pp;
809 unsigned int offset, ihl, verdict; 810 unsigned int offset, ihl, verdict;
@@ -860,8 +861,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
860 861
861 offset += cih->ihl * 4; 862 offset += cih->ihl * 4;
862 863
864 ip_vs_fill_iphdr(AF_INET, cih, &ciph);
863 /* The embedded headers contain source and dest in reverse order */ 865 /* The embedded headers contain source and dest in reverse order */
864 cp = pp->conn_in_get(skb, pp, cih, offset, 1); 866 cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
865 if (!cp) 867 if (!cp)
866 return NF_ACCEPT; 868 return NF_ACCEPT;
867 869
@@ -897,11 +899,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
897 const struct net_device *in, const struct net_device *out, 899 const struct net_device *in, const struct net_device *out,
898 int (*okfn)(struct sk_buff *)) 900 int (*okfn)(struct sk_buff *))
899{ 901{
900 struct iphdr *iph; 902 struct ip_vs_iphdr iph;
901 struct ip_vs_protocol *pp; 903 struct ip_vs_protocol *pp;
902 struct ip_vs_conn *cp; 904 struct ip_vs_conn *cp;
903 int ret, restart; 905 int ret, restart;
904 int ihl; 906
907 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
905 908
906 /* 909 /*
907 * Big tappo: only PACKET_HOST (neither loopback nor mcasts) 910 * Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@@ -909,38 +912,35 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
909 */ 912 */
910 if (unlikely(skb->pkt_type != PACKET_HOST 913 if (unlikely(skb->pkt_type != PACKET_HOST
911 || skb->dev->flags & IFF_LOOPBACK || skb->sk)) { 914 || skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
912 IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", 915 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
913 skb->pkt_type, 916 skb->pkt_type,
914 ip_hdr(skb)->protocol, 917 iph.protocol,
915 NIPQUAD(ip_hdr(skb)->daddr)); 918 IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
916 return NF_ACCEPT; 919 return NF_ACCEPT;
917 } 920 }
918 921
919 iph = ip_hdr(skb); 922 if (unlikely(iph.protocol == IPPROTO_ICMP)) {
920 if (unlikely(iph->protocol == IPPROTO_ICMP)) {
921 int related, verdict = ip_vs_in_icmp(skb, &related, hooknum); 923 int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
922 924
923 if (related) 925 if (related)
924 return verdict; 926 return verdict;
925 iph = ip_hdr(skb); 927 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
926 } 928 }
927 929
928 /* Protocol supported? */ 930 /* Protocol supported? */
929 pp = ip_vs_proto_get(iph->protocol); 931 pp = ip_vs_proto_get(iph.protocol);
930 if (unlikely(!pp)) 932 if (unlikely(!pp))
931 return NF_ACCEPT; 933 return NF_ACCEPT;
932 934
933 ihl = iph->ihl << 2;
934
935 /* 935 /*
936 * Check if the packet belongs to an existing connection entry 936 * Check if the packet belongs to an existing connection entry
937 */ 937 */
938 cp = pp->conn_in_get(skb, pp, iph, ihl, 0); 938 cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0);
939 939
940 if (unlikely(!cp)) { 940 if (unlikely(!cp)) {
941 int v; 941 int v;
942 942
943 if (!pp->conn_schedule(skb, pp, &v, &cp)) 943 if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
944 return v; 944 return v;
945 } 945 }
946 946
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
index 3f9ebd7639ae..2a361a991745 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
@@ -39,25 +39,23 @@ struct isakmp_hdr {
39 39
40 40
41static struct ip_vs_conn * 41static struct ip_vs_conn *
42ah_esp_conn_in_get(const struct sk_buff *skb, 42ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
43 struct ip_vs_protocol *pp, 43 const struct ip_vs_iphdr *iph, unsigned int proto_off,
44 const struct iphdr *iph,
45 unsigned int proto_off,
46 int inverse) 44 int inverse)
47{ 45{
48 struct ip_vs_conn *cp; 46 struct ip_vs_conn *cp;
49 47
50 if (likely(!inverse)) { 48 if (likely(!inverse)) {
51 cp = ip_vs_conn_in_get(IPPROTO_UDP, 49 cp = ip_vs_conn_in_get(IPPROTO_UDP,
52 iph->saddr, 50 iph->saddr.ip,
53 htons(PORT_ISAKMP), 51 htons(PORT_ISAKMP),
54 iph->daddr, 52 iph->daddr.ip,
55 htons(PORT_ISAKMP)); 53 htons(PORT_ISAKMP));
56 } else { 54 } else {
57 cp = ip_vs_conn_in_get(IPPROTO_UDP, 55 cp = ip_vs_conn_in_get(IPPROTO_UDP,
58 iph->daddr, 56 iph->daddr.ip,
59 htons(PORT_ISAKMP), 57 htons(PORT_ISAKMP),
60 iph->saddr, 58 iph->saddr.ip,
61 htons(PORT_ISAKMP)); 59 htons(PORT_ISAKMP));
62 } 60 }
63 61
@@ -66,12 +64,12 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
66 * We are not sure if the packet is from our 64 * We are not sure if the packet is from our
67 * service, so our conn_schedule hook should return NF_ACCEPT 65 * service, so our conn_schedule hook should return NF_ACCEPT
68 */ 66 */
69 IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet " 67 IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
70 "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", 68 "%s%s %s->%s\n",
71 inverse ? "ICMP+" : "", 69 inverse ? "ICMP+" : "",
72 pp->name, 70 pp->name,
73 NIPQUAD(iph->saddr), 71 IP_VS_DBG_ADDR(af, &iph->saddr),
74 NIPQUAD(iph->daddr)); 72 IP_VS_DBG_ADDR(af, &iph->daddr));
75 } 73 }
76 74
77 return cp; 75 return cp;
@@ -79,32 +77,35 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
79 77
80 78
81static struct ip_vs_conn * 79static struct ip_vs_conn *
82ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 80ah_esp_conn_out_get(int af, const struct sk_buff *skb,
83 const struct iphdr *iph, unsigned int proto_off, int inverse) 81 struct ip_vs_protocol *pp,
82 const struct ip_vs_iphdr *iph,
83 unsigned int proto_off,
84 int inverse)
84{ 85{
85 struct ip_vs_conn *cp; 86 struct ip_vs_conn *cp;
86 87
87 if (likely(!inverse)) { 88 if (likely(!inverse)) {
88 cp = ip_vs_conn_out_get(IPPROTO_UDP, 89 cp = ip_vs_conn_out_get(IPPROTO_UDP,
89 iph->saddr, 90 iph->saddr.ip,
90 htons(PORT_ISAKMP), 91 htons(PORT_ISAKMP),
91 iph->daddr, 92 iph->daddr.ip,
92 htons(PORT_ISAKMP)); 93 htons(PORT_ISAKMP));
93 } else { 94 } else {
94 cp = ip_vs_conn_out_get(IPPROTO_UDP, 95 cp = ip_vs_conn_out_get(IPPROTO_UDP,
95 iph->daddr, 96 iph->daddr.ip,
96 htons(PORT_ISAKMP), 97 htons(PORT_ISAKMP),
97 iph->saddr, 98 iph->saddr.ip,
98 htons(PORT_ISAKMP)); 99 htons(PORT_ISAKMP));
99 } 100 }
100 101
101 if (!cp) { 102 if (!cp) {
102 IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet " 103 IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
103 "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", 104 "%s%s %s->%s\n",
104 inverse ? "ICMP+" : "", 105 inverse ? "ICMP+" : "",
105 pp->name, 106 pp->name,
106 NIPQUAD(iph->saddr), 107 IP_VS_DBG_ADDR(af, &iph->saddr),
107 NIPQUAD(iph->daddr)); 108 IP_VS_DBG_ADDR(af, &iph->daddr));
108 } 109 }
109 110
110 return cp; 111 return cp;
@@ -112,8 +113,7 @@ ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
112 113
113 114
114static int 115static int
115ah_esp_conn_schedule(struct sk_buff *skb, 116ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
116 struct ip_vs_protocol *pp,
117 int *verdict, struct ip_vs_conn **cpp) 117 int *verdict, struct ip_vs_conn **cpp)
118{ 118{
119 /* 119 /*
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index fe93c9e6ff63..9211afa8f303 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -25,8 +25,9 @@
25 25
26 26
27static struct ip_vs_conn * 27static struct ip_vs_conn *
28tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 28tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
29 const struct iphdr *iph, unsigned int proto_off, int inverse) 29 const struct ip_vs_iphdr *iph, unsigned int proto_off,
30 int inverse)
30{ 31{
31 __be16 _ports[2], *pptr; 32 __be16 _ports[2], *pptr;
32 33
@@ -36,18 +37,19 @@ tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
36 37
37 if (likely(!inverse)) { 38 if (likely(!inverse)) {
38 return ip_vs_conn_in_get(iph->protocol, 39 return ip_vs_conn_in_get(iph->protocol,
39 iph->saddr, pptr[0], 40 iph->saddr.ip, pptr[0],
40 iph->daddr, pptr[1]); 41 iph->daddr.ip, pptr[1]);
41 } else { 42 } else {
42 return ip_vs_conn_in_get(iph->protocol, 43 return ip_vs_conn_in_get(iph->protocol,
43 iph->daddr, pptr[1], 44 iph->daddr.ip, pptr[1],
44 iph->saddr, pptr[0]); 45 iph->saddr.ip, pptr[0]);
45 } 46 }
46} 47}
47 48
48static struct ip_vs_conn * 49static struct ip_vs_conn *
49tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 50tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
50 const struct iphdr *iph, unsigned int proto_off, int inverse) 51 const struct ip_vs_iphdr *iph, unsigned int proto_off,
52 int inverse)
51{ 53{
52 __be16 _ports[2], *pptr; 54 __be16 _ports[2], *pptr;
53 55
@@ -57,26 +59,25 @@ tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
57 59
58 if (likely(!inverse)) { 60 if (likely(!inverse)) {
59 return ip_vs_conn_out_get(iph->protocol, 61 return ip_vs_conn_out_get(iph->protocol,
60 iph->saddr, pptr[0], 62 iph->saddr.ip, pptr[0],
61 iph->daddr, pptr[1]); 63 iph->daddr.ip, pptr[1]);
62 } else { 64 } else {
63 return ip_vs_conn_out_get(iph->protocol, 65 return ip_vs_conn_out_get(iph->protocol,
64 iph->daddr, pptr[1], 66 iph->daddr.ip, pptr[1],
65 iph->saddr, pptr[0]); 67 iph->saddr.ip, pptr[0]);
66 } 68 }
67} 69}
68 70
69 71
70static int 72static int
71tcp_conn_schedule(struct sk_buff *skb, 73tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
72 struct ip_vs_protocol *pp,
73 int *verdict, struct ip_vs_conn **cpp) 74 int *verdict, struct ip_vs_conn **cpp)
74{ 75{
75 struct ip_vs_service *svc; 76 struct ip_vs_service *svc;
76 struct tcphdr _tcph, *th; 77 struct tcphdr _tcph, *th;
77 struct ip_vs_iphdr iph; 78 struct ip_vs_iphdr iph;
78 79
79 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 80 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
80 81
81 th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph); 82 th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
82 if (th == NULL) { 83 if (th == NULL) {
@@ -85,8 +86,8 @@ tcp_conn_schedule(struct sk_buff *skb,
85 } 86 }
86 87
87 if (th->syn && 88 if (th->syn &&
88 (svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol, 89 (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
89 &iph.daddr, th->dest))) { 90 th->dest))) {
90 if (ip_vs_todrop()) { 91 if (ip_vs_todrop()) {
91 /* 92 /*
92 * It seems that we are very loaded. 93 * It seems that we are very loaded.
@@ -136,7 +137,7 @@ tcp_snat_handler(struct sk_buff *skb,
136 137
137 if (unlikely(cp->app != NULL)) { 138 if (unlikely(cp->app != NULL)) {
138 /* Some checks before mangling */ 139 /* Some checks before mangling */
139 if (pp->csum_check && !pp->csum_check(skb, pp)) 140 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
140 return 0; 141 return 0;
141 142
142 /* Call application helper if needed */ 143 /* Call application helper if needed */
@@ -182,7 +183,7 @@ tcp_dnat_handler(struct sk_buff *skb,
182 183
183 if (unlikely(cp->app != NULL)) { 184 if (unlikely(cp->app != NULL)) {
184 /* Some checks before mangling */ 185 /* Some checks before mangling */
185 if (pp->csum_check && !pp->csum_check(skb, pp)) 186 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
186 return 0; 187 return 0;
187 188
188 /* 189 /*
@@ -219,21 +220,43 @@ tcp_dnat_handler(struct sk_buff *skb,
219 220
220 221
221static int 222static int
222tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) 223tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
223{ 224{
224 const unsigned int tcphoff = ip_hdrlen(skb); 225 unsigned int tcphoff;
226
227#ifdef CONFIG_IP_VS_IPV6
228 if (af == AF_INET6)
229 tcphoff = sizeof(struct ipv6hdr);
230 else
231#endif
232 tcphoff = ip_hdrlen(skb);
225 233
226 switch (skb->ip_summed) { 234 switch (skb->ip_summed) {
227 case CHECKSUM_NONE: 235 case CHECKSUM_NONE:
228 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 236 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
229 case CHECKSUM_COMPLETE: 237 case CHECKSUM_COMPLETE:
230 if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 238#ifdef CONFIG_IP_VS_IPV6
231 skb->len - tcphoff, 239 if (af == AF_INET6) {
232 ip_hdr(skb)->protocol, skb->csum)) { 240 if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
233 IP_VS_DBG_RL_PKT(0, pp, skb, 0, 241 &ipv6_hdr(skb)->daddr,
234 "Failed checksum for"); 242 skb->len - tcphoff,
235 return 0; 243 ipv6_hdr(skb)->nexthdr,
236 } 244 skb->csum)) {
245 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
246 "Failed checksum for");
247 return 0;
248 }
249 } else
250#endif
251 if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
252 ip_hdr(skb)->daddr,
253 skb->len - tcphoff,
254 ip_hdr(skb)->protocol,
255 skb->csum)) {
256 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
257 "Failed checksum for");
258 return 0;
259 }
237 break; 260 break;
238 default: 261 default:
239 /* No need to checksum. */ 262 /* No need to checksum. */
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index d208ed6eb9fc..d3a1b1f2d10d 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -24,8 +24,9 @@
24#include <net/ip.h> 24#include <net/ip.h>
25 25
26static struct ip_vs_conn * 26static struct ip_vs_conn *
27udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 27udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
28 const struct iphdr *iph, unsigned int proto_off, int inverse) 28 const struct ip_vs_iphdr *iph, unsigned int proto_off,
29 int inverse)
29{ 30{
30 struct ip_vs_conn *cp; 31 struct ip_vs_conn *cp;
31 __be16 _ports[2], *pptr; 32 __be16 _ports[2], *pptr;
@@ -36,12 +37,12 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
36 37
37 if (likely(!inverse)) { 38 if (likely(!inverse)) {
38 cp = ip_vs_conn_in_get(iph->protocol, 39 cp = ip_vs_conn_in_get(iph->protocol,
39 iph->saddr, pptr[0], 40 iph->saddr.ip, pptr[0],
40 iph->daddr, pptr[1]); 41 iph->daddr.ip, pptr[1]);
41 } else { 42 } else {
42 cp = ip_vs_conn_in_get(iph->protocol, 43 cp = ip_vs_conn_in_get(iph->protocol,
43 iph->daddr, pptr[1], 44 iph->daddr.ip, pptr[1],
44 iph->saddr, pptr[0]); 45 iph->saddr.ip, pptr[0]);
45 } 46 }
46 47
47 return cp; 48 return cp;
@@ -49,25 +50,25 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
49 50
50 51
51static struct ip_vs_conn * 52static struct ip_vs_conn *
52udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 53udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
53 const struct iphdr *iph, unsigned int proto_off, int inverse) 54 const struct ip_vs_iphdr *iph, unsigned int proto_off,
55 int inverse)
54{ 56{
55 struct ip_vs_conn *cp; 57 struct ip_vs_conn *cp;
56 __be16 _ports[2], *pptr; 58 __be16 _ports[2], *pptr;
57 59
58 pptr = skb_header_pointer(skb, ip_hdrlen(skb), 60 pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
59 sizeof(_ports), _ports);
60 if (pptr == NULL) 61 if (pptr == NULL)
61 return NULL; 62 return NULL;
62 63
63 if (likely(!inverse)) { 64 if (likely(!inverse)) {
64 cp = ip_vs_conn_out_get(iph->protocol, 65 cp = ip_vs_conn_out_get(iph->protocol,
65 iph->saddr, pptr[0], 66 iph->saddr.ip, pptr[0],
66 iph->daddr, pptr[1]); 67 iph->daddr.ip, pptr[1]);
67 } else { 68 } else {
68 cp = ip_vs_conn_out_get(iph->protocol, 69 cp = ip_vs_conn_out_get(iph->protocol,
69 iph->daddr, pptr[1], 70 iph->daddr.ip, pptr[1],
70 iph->saddr, pptr[0]); 71 iph->saddr.ip, pptr[0]);
71 } 72 }
72 73
73 return cp; 74 return cp;
@@ -75,14 +76,14 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
75 76
76 77
77static int 78static int
78udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, 79udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
79 int *verdict, struct ip_vs_conn **cpp) 80 int *verdict, struct ip_vs_conn **cpp)
80{ 81{
81 struct ip_vs_service *svc; 82 struct ip_vs_service *svc;
82 struct udphdr _udph, *uh; 83 struct udphdr _udph, *uh;
83 struct ip_vs_iphdr iph; 84 struct ip_vs_iphdr iph;
84 85
85 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 86 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
86 87
87 uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph); 88 uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
88 if (uh == NULL) { 89 if (uh == NULL) {
@@ -90,7 +91,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
90 return 0; 91 return 0;
91 } 92 }
92 93
93 svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol, 94 svc = ip_vs_service_get(af, skb->mark, iph.protocol,
94 &iph.daddr, uh->dest); 95 &iph.daddr, uh->dest);
95 if (svc) { 96 if (svc) {
96 if (ip_vs_todrop()) { 97 if (ip_vs_todrop()) {
@@ -143,7 +144,7 @@ udp_snat_handler(struct sk_buff *skb,
143 144
144 if (unlikely(cp->app != NULL)) { 145 if (unlikely(cp->app != NULL)) {
145 /* Some checks before mangling */ 146 /* Some checks before mangling */
146 if (pp->csum_check && !pp->csum_check(skb, pp)) 147 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
147 return 0; 148 return 0;
148 149
149 /* 150 /*
@@ -195,7 +196,7 @@ udp_dnat_handler(struct sk_buff *skb,
195 196
196 if (unlikely(cp->app != NULL)) { 197 if (unlikely(cp->app != NULL)) {
197 /* Some checks before mangling */ 198 /* Some checks before mangling */
198 if (pp->csum_check && !pp->csum_check(skb, pp)) 199 if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
199 return 0; 200 return 0;
200 201
201 /* 202 /*
@@ -234,10 +235,17 @@ udp_dnat_handler(struct sk_buff *skb,
234 235
235 236
236static int 237static int
237udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) 238udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
238{ 239{
239 struct udphdr _udph, *uh; 240 struct udphdr _udph, *uh;
240 const unsigned int udphoff = ip_hdrlen(skb); 241 unsigned int udphoff;
242
243#ifdef CONFIG_IP_VS_IPV6
244 if (af == AF_INET6)
245 udphoff = sizeof(struct ipv6hdr);
246 else
247#endif
248 udphoff = ip_hdrlen(skb);
241 249
242 uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph); 250 uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
243 if (uh == NULL) 251 if (uh == NULL)
@@ -249,15 +257,28 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
249 skb->csum = skb_checksum(skb, udphoff, 257 skb->csum = skb_checksum(skb, udphoff,
250 skb->len - udphoff, 0); 258 skb->len - udphoff, 0);
251 case CHECKSUM_COMPLETE: 259 case CHECKSUM_COMPLETE:
252 if (csum_tcpudp_magic(ip_hdr(skb)->saddr, 260#ifdef CONFIG_IP_VS_IPV6
253 ip_hdr(skb)->daddr, 261 if (af == AF_INET6) {
254 skb->len - udphoff, 262 if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
255 ip_hdr(skb)->protocol, 263 &ipv6_hdr(skb)->daddr,
256 skb->csum)) { 264 skb->len - udphoff,
257 IP_VS_DBG_RL_PKT(0, pp, skb, 0, 265 ipv6_hdr(skb)->nexthdr,
258 "Failed checksum for"); 266 skb->csum)) {
259 return 0; 267 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
260 } 268 "Failed checksum for");
269 return 0;
270 }
271 } else
272#endif
273 if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
274 ip_hdr(skb)->daddr,
275 skb->len - udphoff,
276 ip_hdr(skb)->protocol,
277 skb->csum)) {
278 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
279 "Failed checksum for");
280 return 0;
281 }
261 break; 282 break;
262 default: 283 default:
263 /* No need to checksum. */ 284 /* No need to checksum. */