aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipvs
diff options
context:
space:
mode:
authorJulius Volz <juliusv@google.com>2008-09-02 09:55:47 -0400
committerSimon Horman <horms@verge.net.au>2008-09-04 21:17:09 -0400
commit2a3b791e6e1169f374224d164738e9f7be703d77 (patch)
tree2dcbe488eeb00a4fae70b209aea5fe6a3ecb5ae9 /net/ipv4/ipvs
parentcd17f9ed099ed27e9b0d298253e5c05e335ac656 (diff)
IPVS: Add/adjust Netfilter hook functions and helpers for v6
Add Netfilter hook functions or modify existing ones, if possible, to process IPv6 packets. Some support functions are also added/modified for this. ip_vs_nat_icmp_v6() was already added in the patch that added the v6 xmit functions, as it is called from one of them. Signed-off-by: Julius Volz <juliusv@google.com> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net/ipv4/ipvs')
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c365
1 files changed, 329 insertions, 36 deletions
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 8bfd7c2f0ebe..035a511e12f7 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -39,6 +39,11 @@
39#include <linux/netfilter.h> 39#include <linux/netfilter.h>
40#include <linux/netfilter_ipv4.h> 40#include <linux/netfilter_ipv4.h>
41 41
42#ifdef CONFIG_IP_VS_IPV6
43#include <net/ipv6.h>
44#include <linux/netfilter_ipv6.h>
45#endif
46
42#include <net/ip_vs.h> 47#include <net/ip_vs.h>
43 48
44 49
@@ -60,6 +65,7 @@ EXPORT_SYMBOL(ip_vs_get_debug_level);
60 65
61/* ID used in ICMP lookups */ 66/* ID used in ICMP lookups */
62#define icmp_id(icmph) (((icmph)->un).echo.id) 67#define icmp_id(icmph) (((icmph)->un).echo.id)
68#define icmpv6_id(icmph) (icmph->icmp6_dataun.u_echo.identifier)
63 69
64const char *ip_vs_proto_name(unsigned proto) 70const char *ip_vs_proto_name(unsigned proto)
65{ 71{
@@ -74,6 +80,10 @@ const char *ip_vs_proto_name(unsigned proto)
74 return "TCP"; 80 return "TCP";
75 case IPPROTO_ICMP: 81 case IPPROTO_ICMP:
76 return "ICMP"; 82 return "ICMP";
83#ifdef CONFIG_IP_VS_IPV6
84 case IPPROTO_ICMPV6:
85 return "ICMPv6";
86#endif
77 default: 87 default:
78 sprintf(buf, "IP_%d", proto); 88 sprintf(buf, "IP_%d", proto);
79 return buf; 89 return buf;
@@ -425,7 +435,8 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
425{ 435{
426 __be16 _ports[2], *pptr; 436 __be16 _ports[2], *pptr;
427 struct ip_vs_iphdr iph; 437 struct ip_vs_iphdr iph;
428 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 438 int unicast;
439 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
429 440
430 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports); 441 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
431 if (pptr == NULL) { 442 if (pptr == NULL) {
@@ -433,11 +444,17 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
433 return NF_DROP; 444 return NF_DROP;
434 } 445 }
435 446
447#ifdef CONFIG_IP_VS_IPV6
448 if (svc->af == AF_INET6)
449 unicast = ipv6_addr_type(&iph.daddr.in6) & IPV6_ADDR_UNICAST;
450 else
451#endif
452 unicast = (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST);
453
436 /* if it is fwmark-based service, the cache_bypass sysctl is up 454 /* if it is fwmark-based service, the cache_bypass sysctl is up
437 and the destination is RTN_UNICAST (and not local), then create 455 and the destination is a non-local unicast, then create
438 a cache_bypass connection entry */ 456 a cache_bypass connection entry */
439 if (sysctl_ip_vs_cache_bypass && svc->fwmark 457 if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
440 && (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST)) {
441 int ret, cs; 458 int ret, cs;
442 struct ip_vs_conn *cp; 459 struct ip_vs_conn *cp;
443 460
@@ -445,7 +462,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
445 462
446 /* create a new connection entry */ 463 /* create a new connection entry */
447 IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n"); 464 IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
448 cp = ip_vs_conn_new(AF_INET, iph.protocol, 465 cp = ip_vs_conn_new(svc->af, iph.protocol,
449 &iph.saddr, pptr[0], 466 &iph.saddr, pptr[0],
450 &iph.daddr, pptr[1], 467 &iph.daddr, pptr[1],
451 0, 0, 468 0, 0,
@@ -489,7 +506,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
489 * created, the TCP RST packet cannot be sent, instead that 506 * created, the TCP RST packet cannot be sent, instead that
490 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ 507 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
491 */ 508 */
492 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 509#ifdef CONFIG_IP_VS_IPV6
510 if (svc->af == AF_INET6)
511 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0,
512 skb->dev);
513 else
514#endif
515 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
516
493 return NF_DROP; 517 return NF_DROP;
494} 518}
495 519
@@ -528,6 +552,14 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
528 return err; 552 return err;
529} 553}
530 554
555#ifdef CONFIG_IP_VS_IPV6
556static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
557{
558 /* TODO IPv6: Find out what to do here for IPv6 */
559 return 0;
560}
561#endif
562
531/* 563/*
532 * Packet has been made sufficiently writable in caller 564 * Packet has been made sufficiently writable in caller
533 * - inout: 1=in->out, 0=out->in 565 * - inout: 1=in->out, 0=out->in
@@ -727,11 +759,117 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
727 return verdict; 759 return verdict;
728} 760}
729 761
730static inline int is_tcp_reset(const struct sk_buff *skb) 762#ifdef CONFIG_IP_VS_IPV6
763static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
764{
765 struct ipv6hdr *iph;
766 struct icmp6hdr _icmph, *ic;
767 struct ipv6hdr _ciph, *cih; /* The ip header contained
768 within the ICMP */
769 struct ip_vs_iphdr ciph;
770 struct ip_vs_conn *cp;
771 struct ip_vs_protocol *pp;
772 unsigned int offset, verdict;
773
774 *related = 1;
775
776 /* reassemble IP fragments */
777 if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
778 if (ip_vs_gather_frags_v6(skb, IP_DEFRAG_VS_OUT))
779 return NF_STOLEN;
780 }
781
782 iph = ipv6_hdr(skb);
783 offset = sizeof(struct ipv6hdr);
784 ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
785 if (ic == NULL)
786 return NF_DROP;
787
788 IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
789 ic->icmp6_type, ntohs(icmpv6_id(ic)),
790 NIP6(iph->saddr), NIP6(iph->daddr));
791
792 /*
793 * Work through seeing if this is for us.
794 * These checks are supposed to be in an order that means easy
795 * things are checked first to speed up processing.... however
796 * this means that some packets will manage to get a long way
797 * down this stack and then be rejected, but that's life.
798 */
799 if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
800 (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
801 (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
802 *related = 0;
803 return NF_ACCEPT;
804 }
805
806 /* Now find the contained IP header */
807 offset += sizeof(_icmph);
808 cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
809 if (cih == NULL)
810 return NF_ACCEPT; /* The packet looks wrong, ignore */
811
812 pp = ip_vs_proto_get(cih->nexthdr);
813 if (!pp)
814 return NF_ACCEPT;
815
816 /* Is the embedded protocol header present? */
817 /* TODO: we don't support fragmentation at the moment anyways */
818 if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
819 return NF_ACCEPT;
820
821 IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMPv6 for");
822
823 offset += sizeof(struct ipv6hdr);
824
825 ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
826 /* The embedded headers contain source and dest in reverse order */
827 cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
828 if (!cp)
829 return NF_ACCEPT;
830
831 verdict = NF_DROP;
832
833 if (IP_VS_FWD_METHOD(cp) != 0) {
834 IP_VS_ERR("shouldn't reach here, because the box is on the "
835 "half connection in the tun/dr module.\n");
836 }
837
838 /* Ensure the checksum is correct */
839 if (!skb_csum_unnecessary(skb)
840 && ip_vs_checksum_complete(skb, sizeof(struct ipv6hdr))) {
841 /* Failed checksum! */
842 IP_VS_DBG(1, "Forward ICMPv6: failed checksum from "
843 NIP6_FMT "!\n",
844 NIP6(iph->saddr));
845 goto out;
846 }
847
848 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
849 offset += 2 * sizeof(__u16);
850 if (!skb_make_writable(skb, offset))
851 goto out;
852
853 ip_vs_nat_icmp_v6(skb, pp, cp, 1);
854
855 /* do the statistics and put it back */
856 ip_vs_out_stats(cp, skb);
857
858 skb->ipvs_property = 1;
859 verdict = NF_ACCEPT;
860
861out:
862 __ip_vs_conn_put(cp);
863
864 return verdict;
865}
866#endif
867
868static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
731{ 869{
732 struct tcphdr _tcph, *th; 870 struct tcphdr _tcph, *th;
733 871
734 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 872 th = skb_header_pointer(skb, nh_len, sizeof(_tcph), &_tcph);
735 if (th == NULL) 873 if (th == NULL)
736 return 0; 874 return 0;
737 return th->rst; 875 return th->rst;
@@ -750,38 +888,64 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
750 struct ip_vs_iphdr iph; 888 struct ip_vs_iphdr iph;
751 struct ip_vs_protocol *pp; 889 struct ip_vs_protocol *pp;
752 struct ip_vs_conn *cp; 890 struct ip_vs_conn *cp;
891 int af;
753 892
754 EnterFunction(11); 893 EnterFunction(11);
755 894
895 af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
896
756 if (skb->ipvs_property) 897 if (skb->ipvs_property)
757 return NF_ACCEPT; 898 return NF_ACCEPT;
758 899
759 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 900 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
760 if (unlikely(iph.protocol == IPPROTO_ICMP)) { 901#ifdef CONFIG_IP_VS_IPV6
761 int related, verdict = ip_vs_out_icmp(skb, &related); 902 if (af == AF_INET6) {
903 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
904 int related, verdict = ip_vs_out_icmp_v6(skb, &related);
762 905
763 if (related) 906 if (related)
764 return verdict; 907 return verdict;
765 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 908 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
766 } 909 }
910 } else
911#endif
912 if (unlikely(iph.protocol == IPPROTO_ICMP)) {
913 int related, verdict = ip_vs_out_icmp(skb, &related);
914
915 if (related)
916 return verdict;
917 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
918 }
767 919
768 pp = ip_vs_proto_get(iph.protocol); 920 pp = ip_vs_proto_get(iph.protocol);
769 if (unlikely(!pp)) 921 if (unlikely(!pp))
770 return NF_ACCEPT; 922 return NF_ACCEPT;
771 923
772 /* reassemble IP fragments */ 924 /* reassemble IP fragments */
773 if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) && 925#ifdef CONFIG_IP_VS_IPV6
774 !pp->dont_defrag)) { 926 if (af == AF_INET6) {
775 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) 927 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
776 return NF_STOLEN; 928 int related, verdict = ip_vs_out_icmp_v6(skb, &related);
777 929
778 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 930 if (related)
779 } 931 return verdict;
932
933 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
934 }
935 } else
936#endif
937 if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
938 !pp->dont_defrag)) {
939 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
940 return NF_STOLEN;
941
942 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
943 }
780 944
781 /* 945 /*
782 * Check if the packet belongs to an existing entry 946 * Check if the packet belongs to an existing entry
783 */ 947 */
784 cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0); 948 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
785 949
786 if (unlikely(!cp)) { 950 if (unlikely(!cp)) {
787 if (sysctl_ip_vs_nat_icmp_send && 951 if (sysctl_ip_vs_nat_icmp_send &&
@@ -794,16 +958,26 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
794 if (pptr == NULL) 958 if (pptr == NULL)
795 return NF_ACCEPT; /* Not for me */ 959 return NF_ACCEPT; /* Not for me */
796 if (ip_vs_lookup_real_service(iph.protocol, 960 if (ip_vs_lookup_real_service(iph.protocol,
797 iph.saddr.ip, pptr[0])) { 961 iph.saddr.ip,
962 pptr[0])) {
798 /* 963 /*
799 * Notify the real server: there is no 964 * Notify the real server: there is no
800 * existing entry if it is not RST 965 * existing entry if it is not RST
801 * packet or not TCP packet. 966 * packet or not TCP packet.
802 */ 967 */
803 if (iph.protocol != IPPROTO_TCP 968 if (iph.protocol != IPPROTO_TCP
804 || !is_tcp_reset(skb)) { 969 || !is_tcp_reset(skb, iph.len)) {
805 icmp_send(skb,ICMP_DEST_UNREACH, 970#ifdef CONFIG_IP_VS_IPV6
806 ICMP_PORT_UNREACH, 0); 971 if (af == AF_INET6)
972 icmpv6_send(skb,
973 ICMPV6_DEST_UNREACH,
974 ICMPV6_PORT_UNREACH,
975 0, skb->dev);
976 else
977#endif
978 icmp_send(skb,
979 ICMP_DEST_UNREACH,
980 ICMP_PORT_UNREACH, 0);
807 return NF_DROP; 981 return NF_DROP;
808 } 982 }
809 } 983 }
@@ -821,8 +995,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
821 /* mangle the packet */ 995 /* mangle the packet */
822 if (pp->snat_handler && !pp->snat_handler(skb, pp, cp)) 996 if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
823 goto drop; 997 goto drop;
824 ip_hdr(skb)->saddr = cp->vaddr.ip; 998
825 ip_send_check(ip_hdr(skb)); 999#ifdef CONFIG_IP_VS_IPV6
1000 if (af == AF_INET6)
1001 ipv6_hdr(skb)->saddr = cp->vaddr.in6;
1002 else
1003#endif
1004 {
1005 ip_hdr(skb)->saddr = cp->vaddr.ip;
1006 ip_send_check(ip_hdr(skb));
1007 }
826 1008
827 /* For policy routing, packets originating from this 1009 /* For policy routing, packets originating from this
828 * machine itself may be routed differently to packets 1010 * machine itself may be routed differently to packets
@@ -830,8 +1012,14 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
830 * if it came from this machine itself. So re-compute 1012 * if it came from this machine itself. So re-compute
831 * the routing information. 1013 * the routing information.
832 */ 1014 */
833 if (ip_route_me_harder(skb, RTN_LOCAL) != 0) 1015#ifdef CONFIG_IP_VS_IPV6
834 goto drop; 1016 if (af == AF_INET6) {
1017 if (ip6_route_me_harder(skb) != 0)
1018 goto drop;
1019 } else
1020#endif
1021 if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
1022 goto drop;
835 1023
836 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); 1024 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
837 1025
@@ -949,6 +1137,94 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
949 return verdict; 1137 return verdict;
950} 1138}
951 1139
1140#ifdef CONFIG_IP_VS_IPV6
1141static int
1142ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1143{
1144 struct ipv6hdr *iph;
1145 struct icmp6hdr _icmph, *ic;
1146 struct ipv6hdr _ciph, *cih; /* The ip header contained
1147 within the ICMP */
1148 struct ip_vs_iphdr ciph;
1149 struct ip_vs_conn *cp;
1150 struct ip_vs_protocol *pp;
1151 unsigned int offset, verdict;
1152
1153 *related = 1;
1154
1155 /* reassemble IP fragments */
1156 if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
1157 if (ip_vs_gather_frags_v6(skb, hooknum == NF_INET_LOCAL_IN ?
1158 IP_DEFRAG_VS_IN :
1159 IP_DEFRAG_VS_FWD))
1160 return NF_STOLEN;
1161 }
1162
1163 iph = ipv6_hdr(skb);
1164 offset = sizeof(struct ipv6hdr);
1165 ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
1166 if (ic == NULL)
1167 return NF_DROP;
1168
1169 IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
1170 ic->icmp6_type, ntohs(icmpv6_id(ic)),
1171 NIP6(iph->saddr), NIP6(iph->daddr));
1172
1173 /*
1174 * Work through seeing if this is for us.
1175 * These checks are supposed to be in an order that means easy
1176 * things are checked first to speed up processing.... however
1177 * this means that some packets will manage to get a long way
1178 * down this stack and then be rejected, but that's life.
1179 */
1180 if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
1181 (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
1182 (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
1183 *related = 0;
1184 return NF_ACCEPT;
1185 }
1186
1187 /* Now find the contained IP header */
1188 offset += sizeof(_icmph);
1189 cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
1190 if (cih == NULL)
1191 return NF_ACCEPT; /* The packet looks wrong, ignore */
1192
1193 pp = ip_vs_proto_get(cih->nexthdr);
1194 if (!pp)
1195 return NF_ACCEPT;
1196
1197 /* Is the embedded protocol header present? */
1198 /* TODO: we don't support fragmentation at the moment anyways */
1199 if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
1200 return NF_ACCEPT;
1201
1202 IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMPv6 for");
1203
1204 offset += sizeof(struct ipv6hdr);
1205
1206 ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
1207 /* The embedded headers contain source and dest in reverse order */
1208 cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1);
1209 if (!cp)
1210 return NF_ACCEPT;
1211
1212 verdict = NF_DROP;
1213
1214 /* do the statistics and put it back */
1215 ip_vs_in_stats(cp, skb);
1216 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
1217 offset += 2 * sizeof(__u16);
1218 verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
1219 /* do not touch skb anymore */
1220
1221 __ip_vs_conn_put(cp);
1222
1223 return verdict;
1224}
1225#endif
1226
1227
952/* 1228/*
953 * Check if it's for virtual services, look it up, 1229 * Check if it's for virtual services, look it up,
954 * and send it on its way... 1230 * and send it on its way...
@@ -961,9 +1237,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
961 struct ip_vs_iphdr iph; 1237 struct ip_vs_iphdr iph;
962 struct ip_vs_protocol *pp; 1238 struct ip_vs_protocol *pp;
963 struct ip_vs_conn *cp; 1239 struct ip_vs_conn *cp;
964 int ret, restart; 1240 int ret, restart, af;
1241
1242 af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
965 1243
966 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 1244 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
967 1245
968 /* 1246 /*
969 * Big tappo: only PACKET_HOST (neither loopback nor mcasts) 1247 * Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@@ -974,7 +1252,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
974 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n", 1252 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
975 skb->pkt_type, 1253 skb->pkt_type,
976 iph.protocol, 1254 iph.protocol,
977 IP_VS_DBG_ADDR(AF_INET, &iph.daddr)); 1255 IP_VS_DBG_ADDR(af, &iph.daddr));
978 return NF_ACCEPT; 1256 return NF_ACCEPT;
979 } 1257 }
980 1258
@@ -983,7 +1261,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
983 1261
984 if (related) 1262 if (related)
985 return verdict; 1263 return verdict;
986 ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); 1264 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
987 } 1265 }
988 1266
989 /* Protocol supported? */ 1267 /* Protocol supported? */
@@ -994,12 +1272,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
994 /* 1272 /*
995 * Check if the packet belongs to an existing connection entry 1273 * Check if the packet belongs to an existing connection entry
996 */ 1274 */
997 cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0); 1275 cp = pp->conn_in_get(af, skb, pp, &iph, iph.len, 0);
998 1276
999 if (unlikely(!cp)) { 1277 if (unlikely(!cp)) {
1000 int v; 1278 int v;
1001 1279
1002 if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp)) 1280 if (!pp->conn_schedule(af, skb, pp, &v, &cp))
1003 return v; 1281 return v;
1004 } 1282 }
1005 1283
@@ -1082,6 +1360,21 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
1082 return ip_vs_in_icmp(skb, &r, hooknum); 1360 return ip_vs_in_icmp(skb, &r, hooknum);
1083} 1361}
1084 1362
1363#ifdef CONFIG_IP_VS_IPV6
1364static unsigned int
1365ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1366 const struct net_device *in, const struct net_device *out,
1367 int (*okfn)(struct sk_buff *))
1368{
1369 int r;
1370
1371 if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
1372 return NF_ACCEPT;
1373
1374 return ip_vs_in_icmp_v6(skb, &r, hooknum);
1375}
1376#endif
1377
1085 1378
1086static struct nf_hook_ops ip_vs_ops[] __read_mostly = { 1379static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1087 /* After packet filtering, forward packet through VS/DR, VS/TUN, 1380 /* After packet filtering, forward packet through VS/DR, VS/TUN,