aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-09 22:51:04 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-09 22:51:04 -0400
commitdacc62dbf56e872ad96edde0393b9deb56d80cd5 (patch)
tree3d1b3e25aba9c5324bb0f6289033f502fa6ccb8c
parent47abf28d5b36521558a848a346064a3a3c82bd9e (diff)
parentc051a0a2c9e283c1123ed3ce65e66e41d2ce5e24 (diff)
Merge branch 'lvs-next-2.6' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-2.6
-rw-r--r--include/net/ip_vs.h308
-rw-r--r--net/ipv4/ipvs/Kconfig11
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c249
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c806
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c523
-rw-r--r--net/ipv4/ipvs/ip_vs_dh.c5
-rw-r--r--net/ipv4/ipvs/ip_vs_est.c40
-rw-r--r--net/ipv4/ipvs/ip_vs_ftp.c61
-rw-r--r--net/ipv4/ipvs/ip_vs_lblc.c7
-rw-r--r--net/ipv4/ipvs/ip_vs_lblcr.c11
-rw-r--r--net/ipv4/ipvs/ip_vs_lc.c11
-rw-r--r--net/ipv4/ipvs/ip_vs_nq.c15
-rw-r--r--net/ipv4/ipvs/ip_vs_proto.c65
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_ah_esp.c100
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c253
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c226
-rw-r--r--net/ipv4/ipvs/ip_vs_rr.c13
-rw-r--r--net/ipv4/ipvs/ip_vs_sed.c15
-rw-r--r--net/ipv4/ipvs/ip_vs_sh.c5
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c40
-rw-r--r--net/ipv4/ipvs/ip_vs_wlc.c15
-rw-r--r--net/ipv4/ipvs/ip_vs_wrr.c15
-rw-r--r--net/ipv4/ipvs/ip_vs_xmit.c471
23 files changed, 2469 insertions, 796 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index a25ad243031d..33e2ac6ceb3e 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -21,11 +21,103 @@
21#include <linux/timer.h> 21#include <linux/timer.h>
22 22
23#include <net/checksum.h> 23#include <net/checksum.h>
24#include <linux/netfilter.h> /* for union nf_inet_addr */
25#include <linux/ipv6.h> /* for struct ipv6hdr */
26#include <net/ipv6.h> /* for ipv6_addr_copy */
27
28struct ip_vs_iphdr {
29 int len;
30 __u8 protocol;
31 union nf_inet_addr saddr;
32 union nf_inet_addr daddr;
33};
34
35static inline void
36ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr)
37{
38#ifdef CONFIG_IP_VS_IPV6
39 if (af == AF_INET6) {
40 const struct ipv6hdr *iph = nh;
41 iphdr->len = sizeof(struct ipv6hdr);
42 iphdr->protocol = iph->nexthdr;
43 ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr);
44 ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr);
45 } else
46#endif
47 {
48 const struct iphdr *iph = nh;
49 iphdr->len = iph->ihl * 4;
50 iphdr->protocol = iph->protocol;
51 iphdr->saddr.ip = iph->saddr;
52 iphdr->daddr.ip = iph->daddr;
53 }
54}
55
56static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
57 const union nf_inet_addr *src)
58{
59#ifdef CONFIG_IP_VS_IPV6
60 if (af == AF_INET6)
61 ipv6_addr_copy(&dst->in6, &src->in6);
62 else
63#endif
64 dst->ip = src->ip;
65}
66
67static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
68 const union nf_inet_addr *b)
69{
70#ifdef CONFIG_IP_VS_IPV6
71 if (af == AF_INET6)
72 return ipv6_addr_equal(&a->in6, &b->in6);
73#endif
74 return a->ip == b->ip;
75}
24 76
25#ifdef CONFIG_IP_VS_DEBUG 77#ifdef CONFIG_IP_VS_DEBUG
26#include <linux/net.h> 78#include <linux/net.h>
27 79
28extern int ip_vs_get_debug_level(void); 80extern int ip_vs_get_debug_level(void);
81
82static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
83 const union nf_inet_addr *addr,
84 int *idx)
85{
86 int len;
87#ifdef CONFIG_IP_VS_IPV6
88 if (af == AF_INET6)
89 len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
90 NIP6(addr->in6)) + 1;
91 else
92#endif
93 len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
94 NIPQUAD(addr->ip)) + 1;
95
96 *idx += len;
97 BUG_ON(*idx > buf_len + 1);
98 return &buf[*idx - len];
99}
100
101#define IP_VS_DBG_BUF(level, msg...) \
102 do { \
103 char ip_vs_dbg_buf[160]; \
104 int ip_vs_dbg_idx = 0; \
105 if (level <= ip_vs_get_debug_level()) \
106 printk(KERN_DEBUG "IPVS: " msg); \
107 } while (0)
108#define IP_VS_ERR_BUF(msg...) \
109 do { \
110 char ip_vs_dbg_buf[160]; \
111 int ip_vs_dbg_idx = 0; \
112 printk(KERN_ERR "IPVS: " msg); \
113 } while (0)
114
115/* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */
116#define IP_VS_DBG_ADDR(af, addr) \
117 ip_vs_dbg_addr(af, ip_vs_dbg_buf, \
118 sizeof(ip_vs_dbg_buf), addr, \
119 &ip_vs_dbg_idx)
120
29#define IP_VS_DBG(level, msg...) \ 121#define IP_VS_DBG(level, msg...) \
30 do { \ 122 do { \
31 if (level <= ip_vs_get_debug_level()) \ 123 if (level <= ip_vs_get_debug_level()) \
@@ -48,6 +140,8 @@ extern int ip_vs_get_debug_level(void);
48 pp->debug_packet(pp, skb, ofs, msg); \ 140 pp->debug_packet(pp, skb, ofs, msg); \
49 } while (0) 141 } while (0)
50#else /* NO DEBUGGING at ALL */ 142#else /* NO DEBUGGING at ALL */
143#define IP_VS_DBG_BUF(level, msg...) do {} while (0)
144#define IP_VS_ERR_BUF(msg...) do {} while (0)
51#define IP_VS_DBG(level, msg...) do {} while (0) 145#define IP_VS_DBG(level, msg...) do {} while (0)
52#define IP_VS_DBG_RL(msg...) do {} while (0) 146#define IP_VS_DBG_RL(msg...) do {} while (0)
53#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) do {} while (0) 147#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) do {} while (0)
@@ -160,27 +254,10 @@ struct ip_vs_estimator {
160 254
161struct ip_vs_stats 255struct ip_vs_stats
162{ 256{
163 __u32 conns; /* connections scheduled */ 257 struct ip_vs_stats_user ustats; /* statistics */
164 __u32 inpkts; /* incoming packets */ 258 struct ip_vs_estimator est; /* estimator */
165 __u32 outpkts; /* outgoing packets */
166 __u64 inbytes; /* incoming bytes */
167 __u64 outbytes; /* outgoing bytes */
168
169 __u32 cps; /* current connection rate */
170 __u32 inpps; /* current in packet rate */
171 __u32 outpps; /* current out packet rate */
172 __u32 inbps; /* current in byte rate */
173 __u32 outbps; /* current out byte rate */
174
175 /*
176 * Don't add anything before the lock, because we use memcpy() to copy
177 * the members before the lock to struct ip_vs_stats_user in
178 * ip_vs_ctl.c.
179 */
180 259
181 spinlock_t lock; /* spin lock */ 260 spinlock_t lock; /* spin lock */
182
183 struct ip_vs_estimator est; /* estimator */
184}; 261};
185 262
186struct dst_entry; 263struct dst_entry;
@@ -202,21 +279,23 @@ struct ip_vs_protocol {
202 279
203 void (*exit)(struct ip_vs_protocol *pp); 280 void (*exit)(struct ip_vs_protocol *pp);
204 281
205 int (*conn_schedule)(struct sk_buff *skb, 282 int (*conn_schedule)(int af, struct sk_buff *skb,
206 struct ip_vs_protocol *pp, 283 struct ip_vs_protocol *pp,
207 int *verdict, struct ip_vs_conn **cpp); 284 int *verdict, struct ip_vs_conn **cpp);
208 285
209 struct ip_vs_conn * 286 struct ip_vs_conn *
210 (*conn_in_get)(const struct sk_buff *skb, 287 (*conn_in_get)(int af,
288 const struct sk_buff *skb,
211 struct ip_vs_protocol *pp, 289 struct ip_vs_protocol *pp,
212 const struct iphdr *iph, 290 const struct ip_vs_iphdr *iph,
213 unsigned int proto_off, 291 unsigned int proto_off,
214 int inverse); 292 int inverse);
215 293
216 struct ip_vs_conn * 294 struct ip_vs_conn *
217 (*conn_out_get)(const struct sk_buff *skb, 295 (*conn_out_get)(int af,
296 const struct sk_buff *skb,
218 struct ip_vs_protocol *pp, 297 struct ip_vs_protocol *pp,
219 const struct iphdr *iph, 298 const struct ip_vs_iphdr *iph,
220 unsigned int proto_off, 299 unsigned int proto_off,
221 int inverse); 300 int inverse);
222 301
@@ -226,7 +305,8 @@ struct ip_vs_protocol {
226 int (*dnat_handler)(struct sk_buff *skb, 305 int (*dnat_handler)(struct sk_buff *skb,
227 struct ip_vs_protocol *pp, struct ip_vs_conn *cp); 306 struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
228 307
229 int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp); 308 int (*csum_check)(int af, struct sk_buff *skb,
309 struct ip_vs_protocol *pp);
230 310
231 const char *(*state_name)(int state); 311 const char *(*state_name)(int state);
232 312
@@ -259,9 +339,10 @@ struct ip_vs_conn {
259 struct list_head c_list; /* hashed list heads */ 339 struct list_head c_list; /* hashed list heads */
260 340
261 /* Protocol, addresses and port numbers */ 341 /* Protocol, addresses and port numbers */
262 __be32 caddr; /* client address */ 342 u16 af; /* address family */
263 __be32 vaddr; /* virtual address */ 343 union nf_inet_addr caddr; /* client address */
264 __be32 daddr; /* destination address */ 344 union nf_inet_addr vaddr; /* virtual address */
345 union nf_inet_addr daddr; /* destination address */
265 __be16 cport; 346 __be16 cport;
266 __be16 vport; 347 __be16 vport;
267 __be16 dport; 348 __be16 dport;
@@ -305,6 +386,45 @@ struct ip_vs_conn {
305 386
306 387
307/* 388/*
389 * Extended internal versions of struct ip_vs_service_user and
390 * ip_vs_dest_user for IPv6 support.
391 *
392 * We need these to conveniently pass around service and destination
393 * options, but unfortunately, we also need to keep the old definitions to
394 * maintain userspace backwards compatibility for the setsockopt interface.
395 */
396struct ip_vs_service_user_kern {
397 /* virtual service addresses */
398 u16 af;
399 u16 protocol;
400 union nf_inet_addr addr; /* virtual ip address */
401 u16 port;
402 u32 fwmark; /* firwall mark of service */
403
404 /* virtual service options */
405 char *sched_name;
406 unsigned flags; /* virtual service flags */
407 unsigned timeout; /* persistent timeout in sec */
408 u32 netmask; /* persistent netmask */
409};
410
411
412struct ip_vs_dest_user_kern {
413 /* destination server address */
414 union nf_inet_addr addr;
415 u16 port;
416
417 /* real server options */
418 unsigned conn_flags; /* connection flags */
419 int weight; /* destination weight */
420
421 /* thresholds for active connections */
422 u32 u_threshold; /* upper threshold */
423 u32 l_threshold; /* lower threshold */
424};
425
426
427/*
308 * The information about the virtual service offered to the net 428 * The information about the virtual service offered to the net
309 * and the forwarding entries 429 * and the forwarding entries
310 */ 430 */
@@ -314,8 +434,9 @@ struct ip_vs_service {
314 atomic_t refcnt; /* reference counter */ 434 atomic_t refcnt; /* reference counter */
315 atomic_t usecnt; /* use counter */ 435 atomic_t usecnt; /* use counter */
316 436
437 u16 af; /* address family */
317 __u16 protocol; /* which protocol (TCP/UDP) */ 438 __u16 protocol; /* which protocol (TCP/UDP) */
318 __be32 addr; /* IP address for virtual service */ 439 union nf_inet_addr addr; /* IP address for virtual service */
319 __be16 port; /* port number for the service */ 440 __be16 port; /* port number for the service */
320 __u32 fwmark; /* firewall mark of the service */ 441 __u32 fwmark; /* firewall mark of the service */
321 unsigned flags; /* service status flags */ 442 unsigned flags; /* service status flags */
@@ -342,7 +463,8 @@ struct ip_vs_dest {
342 struct list_head n_list; /* for the dests in the service */ 463 struct list_head n_list; /* for the dests in the service */
343 struct list_head d_list; /* for table with all the dests */ 464 struct list_head d_list; /* for table with all the dests */
344 465
345 __be32 addr; /* IP address of the server */ 466 u16 af; /* address family */
467 union nf_inet_addr addr; /* IP address of the server */
346 __be16 port; /* port number of the server */ 468 __be16 port; /* port number of the server */
347 volatile unsigned flags; /* dest status flags */ 469 volatile unsigned flags; /* dest status flags */
348 atomic_t conn_flags; /* flags to copy to conn */ 470 atomic_t conn_flags; /* flags to copy to conn */
@@ -366,7 +488,7 @@ struct ip_vs_dest {
366 /* for virtual service */ 488 /* for virtual service */
367 struct ip_vs_service *svc; /* service it belongs to */ 489 struct ip_vs_service *svc; /* service it belongs to */
368 __u16 protocol; /* which protocol (TCP/UDP) */ 490 __u16 protocol; /* which protocol (TCP/UDP) */
369 __be32 vaddr; /* virtual IP address */ 491 union nf_inet_addr vaddr; /* virtual IP address */
370 __be16 vport; /* virtual port number */ 492 __be16 vport; /* virtual port number */
371 __u32 vfwmark; /* firewall mark of service */ 493 __u32 vfwmark; /* firewall mark of service */
372}; 494};
@@ -380,6 +502,9 @@ struct ip_vs_scheduler {
380 char *name; /* scheduler name */ 502 char *name; /* scheduler name */
381 atomic_t refcnt; /* reference counter */ 503 atomic_t refcnt; /* reference counter */
382 struct module *module; /* THIS_MODULE/NULL */ 504 struct module *module; /* THIS_MODULE/NULL */
505#ifdef CONFIG_IP_VS_IPV6
506 int supports_ipv6; /* scheduler has IPv6 support */
507#endif
383 508
384 /* scheduler initializing service */ 509 /* scheduler initializing service */
385 int (*init_service)(struct ip_vs_service *svc); 510 int (*init_service)(struct ip_vs_service *svc);
@@ -479,16 +604,8 @@ extern void ip_vs_init_hash_table(struct list_head *table, int rows);
479#ifndef CONFIG_IP_VS_TAB_BITS 604#ifndef CONFIG_IP_VS_TAB_BITS
480#define CONFIG_IP_VS_TAB_BITS 12 605#define CONFIG_IP_VS_TAB_BITS 12
481#endif 606#endif
482/* make sure that IP_VS_CONN_TAB_BITS is located in [8, 20] */ 607
483#if CONFIG_IP_VS_TAB_BITS < 8
484#define IP_VS_CONN_TAB_BITS 8
485#endif
486#if CONFIG_IP_VS_TAB_BITS > 20
487#define IP_VS_CONN_TAB_BITS 20
488#endif
489#if 8 <= CONFIG_IP_VS_TAB_BITS && CONFIG_IP_VS_TAB_BITS <= 20
490#define IP_VS_CONN_TAB_BITS CONFIG_IP_VS_TAB_BITS 608#define IP_VS_CONN_TAB_BITS CONFIG_IP_VS_TAB_BITS
491#endif
492#define IP_VS_CONN_TAB_SIZE (1 << IP_VS_CONN_TAB_BITS) 609#define IP_VS_CONN_TAB_SIZE (1 << IP_VS_CONN_TAB_BITS)
493#define IP_VS_CONN_TAB_MASK (IP_VS_CONN_TAB_SIZE - 1) 610#define IP_VS_CONN_TAB_MASK (IP_VS_CONN_TAB_SIZE - 1)
494 611
@@ -500,11 +617,16 @@ enum {
500}; 617};
501 618
502extern struct ip_vs_conn *ip_vs_conn_in_get 619extern struct ip_vs_conn *ip_vs_conn_in_get
503(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port); 620(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
621 const union nf_inet_addr *d_addr, __be16 d_port);
622
504extern struct ip_vs_conn *ip_vs_ct_in_get 623extern struct ip_vs_conn *ip_vs_ct_in_get
505(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port); 624(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
625 const union nf_inet_addr *d_addr, __be16 d_port);
626
506extern struct ip_vs_conn *ip_vs_conn_out_get 627extern struct ip_vs_conn *ip_vs_conn_out_get
507(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port); 628(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
629 const union nf_inet_addr *d_addr, __be16 d_port);
508 630
509/* put back the conn without restarting its timer */ 631/* put back the conn without restarting its timer */
510static inline void __ip_vs_conn_put(struct ip_vs_conn *cp) 632static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -515,8 +637,9 @@ extern void ip_vs_conn_put(struct ip_vs_conn *cp);
515extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport); 637extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
516 638
517extern struct ip_vs_conn * 639extern struct ip_vs_conn *
518ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport, 640ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
519 __be32 daddr, __be16 dport, unsigned flags, 641 const union nf_inet_addr *vaddr, __be16 vport,
642 const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
520 struct ip_vs_dest *dest); 643 struct ip_vs_dest *dest);
521extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp); 644extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
522 645
@@ -532,24 +655,32 @@ static inline void ip_vs_control_del(struct ip_vs_conn *cp)
532{ 655{
533 struct ip_vs_conn *ctl_cp = cp->control; 656 struct ip_vs_conn *ctl_cp = cp->control;
534 if (!ctl_cp) { 657 if (!ctl_cp) {
535 IP_VS_ERR("request control DEL for uncontrolled: " 658 IP_VS_ERR_BUF("request control DEL for uncontrolled: "
536 "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", 659 "%s:%d to %s:%d\n",
537 NIPQUAD(cp->caddr),ntohs(cp->cport), 660 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
538 NIPQUAD(cp->vaddr),ntohs(cp->vport)); 661 ntohs(cp->cport),
662 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
663 ntohs(cp->vport));
664
539 return; 665 return;
540 } 666 }
541 667
542 IP_VS_DBG(7, "DELeting control for: " 668 IP_VS_DBG_BUF(7, "DELeting control for: "
543 "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n", 669 "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
544 NIPQUAD(cp->caddr),ntohs(cp->cport), 670 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
545 NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport)); 671 ntohs(cp->cport),
672 IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
673 ntohs(ctl_cp->cport));
546 674
547 cp->control = NULL; 675 cp->control = NULL;
548 if (atomic_read(&ctl_cp->n_control) == 0) { 676 if (atomic_read(&ctl_cp->n_control) == 0) {
549 IP_VS_ERR("BUG control DEL with n=0 : " 677 IP_VS_ERR_BUF("BUG control DEL with n=0 : "
550 "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", 678 "%s:%d to %s:%d\n",
551 NIPQUAD(cp->caddr),ntohs(cp->cport), 679 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
552 NIPQUAD(cp->vaddr),ntohs(cp->vport)); 680 ntohs(cp->cport),
681 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
682 ntohs(cp->vport));
683
553 return; 684 return;
554 } 685 }
555 atomic_dec(&ctl_cp->n_control); 686 atomic_dec(&ctl_cp->n_control);
@@ -559,17 +690,22 @@ static inline void
559ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp) 690ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
560{ 691{
561 if (cp->control) { 692 if (cp->control) {
562 IP_VS_ERR("request control ADD for already controlled: " 693 IP_VS_ERR_BUF("request control ADD for already controlled: "
563 "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", 694 "%s:%d to %s:%d\n",
564 NIPQUAD(cp->caddr),ntohs(cp->cport), 695 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
565 NIPQUAD(cp->vaddr),ntohs(cp->vport)); 696 ntohs(cp->cport),
697 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
698 ntohs(cp->vport));
699
566 ip_vs_control_del(cp); 700 ip_vs_control_del(cp);
567 } 701 }
568 702
569 IP_VS_DBG(7, "ADDing control for: " 703 IP_VS_DBG_BUF(7, "ADDing control for: "
570 "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n", 704 "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
571 NIPQUAD(cp->caddr),ntohs(cp->cport), 705 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
572 NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport)); 706 ntohs(cp->cport),
707 IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
708 ntohs(ctl_cp->cport));
573 709
574 cp->control = ctl_cp; 710 cp->control = ctl_cp;
575 atomic_inc(&ctl_cp->n_control); 711 atomic_inc(&ctl_cp->n_control);
@@ -647,7 +783,8 @@ extern struct ip_vs_stats ip_vs_stats;
647extern const struct ctl_path net_vs_ctl_path[]; 783extern const struct ctl_path net_vs_ctl_path[];
648 784
649extern struct ip_vs_service * 785extern struct ip_vs_service *
650ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport); 786ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
787 const union nf_inet_addr *vaddr, __be16 vport);
651 788
652static inline void ip_vs_service_put(struct ip_vs_service *svc) 789static inline void ip_vs_service_put(struct ip_vs_service *svc)
653{ 790{
@@ -655,14 +792,16 @@ static inline void ip_vs_service_put(struct ip_vs_service *svc)
655} 792}
656 793
657extern struct ip_vs_dest * 794extern struct ip_vs_dest *
658ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport); 795ip_vs_lookup_real_service(int af, __u16 protocol,
796 const union nf_inet_addr *daddr, __be16 dport);
797
659extern int ip_vs_use_count_inc(void); 798extern int ip_vs_use_count_inc(void);
660extern void ip_vs_use_count_dec(void); 799extern void ip_vs_use_count_dec(void);
661extern int ip_vs_control_init(void); 800extern int ip_vs_control_init(void);
662extern void ip_vs_control_cleanup(void); 801extern void ip_vs_control_cleanup(void);
663extern struct ip_vs_dest * 802extern struct ip_vs_dest *
664ip_vs_find_dest(__be32 daddr, __be16 dport, 803ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport,
665 __be32 vaddr, __be16 vport, __u16 protocol); 804 const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol);
666extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp); 805extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
667 806
668 807
@@ -706,6 +845,19 @@ extern int ip_vs_icmp_xmit
706(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset); 845(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
707extern void ip_vs_dst_reset(struct ip_vs_dest *dest); 846extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
708 847
848#ifdef CONFIG_IP_VS_IPV6
849extern int ip_vs_bypass_xmit_v6
850(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
851extern int ip_vs_nat_xmit_v6
852(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
853extern int ip_vs_tunnel_xmit_v6
854(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
855extern int ip_vs_dr_xmit_v6
856(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
857extern int ip_vs_icmp_xmit_v6
858(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp,
859 int offset);
860#endif
709 861
710/* 862/*
711 * This is a simple mechanism to ignore packets when 863 * This is a simple mechanism to ignore packets when
@@ -750,7 +902,12 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
750} 902}
751 903
752extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp, 904extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
753 struct ip_vs_conn *cp, int dir); 905 struct ip_vs_conn *cp, int dir);
906
907#ifdef CONFIG_IP_VS_IPV6
908extern void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
909 struct ip_vs_conn *cp, int dir);
910#endif
754 911
755extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset); 912extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
756 913
@@ -761,6 +918,17 @@ static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
761 return csum_partial((char *) diff, sizeof(diff), oldsum); 918 return csum_partial((char *) diff, sizeof(diff), oldsum);
762} 919}
763 920
921#ifdef CONFIG_IP_VS_IPV6
922static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new,
923 __wsum oldsum)
924{
925 __be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0],
926 new[3], new[2], new[1], new[0] };
927
928 return csum_partial((char *) diff, sizeof(diff), oldsum);
929}
930#endif
931
764static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum) 932static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
765{ 933{
766 __be16 diff[2] = { ~old, new }; 934 __be16 diff[2] = { ~old, new };
diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
index 2e48a7e27223..de6004de80bc 100644
--- a/net/ipv4/ipvs/Kconfig
+++ b/net/ipv4/ipvs/Kconfig
@@ -24,6 +24,14 @@ menuconfig IP_VS
24 24
25if IP_VS 25if IP_VS
26 26
27config IP_VS_IPV6
28 bool "IPv6 support for IPVS (DANGEROUS)"
29 depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6)
30 ---help---
31 Add IPv6 support to IPVS. This is incomplete and might be dangerous.
32
33 Say N if unsure.
34
27config IP_VS_DEBUG 35config IP_VS_DEBUG
28 bool "IP virtual server debugging" 36 bool "IP virtual server debugging"
29 ---help--- 37 ---help---
@@ -33,7 +41,8 @@ config IP_VS_DEBUG
33 41
34config IP_VS_TAB_BITS 42config IP_VS_TAB_BITS
35 int "IPVS connection table size (the Nth power of 2)" 43 int "IPVS connection table size (the Nth power of 2)"
36 default "12" 44 range 8 20
45 default 12
37 ---help--- 46 ---help---
38 The IPVS connection hash table uses the chaining scheme to handle 47 The IPVS connection hash table uses the chaining scheme to handle
39 hash collisions. Using a big IPVS connection hash table will greatly 48 hash collisions. Using a big IPVS connection hash table will greatly
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 44a6872dc245..9a24332fbed8 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -114,9 +114,18 @@ static inline void ct_write_unlock_bh(unsigned key)
114/* 114/*
115 * Returns hash value for IPVS connection entry 115 * Returns hash value for IPVS connection entry
116 */ 116 */
117static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port) 117static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
118 const union nf_inet_addr *addr,
119 __be16 port)
118{ 120{
119 return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd) 121#ifdef CONFIG_IP_VS_IPV6
122 if (af == AF_INET6)
123 return jhash_3words(jhash(addr, 16, ip_vs_conn_rnd),
124 (__force u32)port, proto, ip_vs_conn_rnd)
125 & IP_VS_CONN_TAB_MASK;
126#endif
127 return jhash_3words((__force u32)addr->ip, (__force u32)port, proto,
128 ip_vs_conn_rnd)
120 & IP_VS_CONN_TAB_MASK; 129 & IP_VS_CONN_TAB_MASK;
121} 130}
122 131
@@ -131,7 +140,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
131 int ret; 140 int ret;
132 141
133 /* Hash by protocol, client address and port */ 142 /* Hash by protocol, client address and port */
134 hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport); 143 hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
135 144
136 ct_write_lock(hash); 145 ct_write_lock(hash);
137 146
@@ -162,7 +171,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
162 int ret; 171 int ret;
163 172
164 /* unhash it and decrease its reference counter */ 173 /* unhash it and decrease its reference counter */
165 hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport); 174 hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
166 175
167 ct_write_lock(hash); 176 ct_write_lock(hash);
168 177
@@ -187,20 +196,23 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
187 * d_addr, d_port: pkt dest address (load balancer) 196 * d_addr, d_port: pkt dest address (load balancer)
188 */ 197 */
189static inline struct ip_vs_conn *__ip_vs_conn_in_get 198static inline struct ip_vs_conn *__ip_vs_conn_in_get
190(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port) 199(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
200 const union nf_inet_addr *d_addr, __be16 d_port)
191{ 201{
192 unsigned hash; 202 unsigned hash;
193 struct ip_vs_conn *cp; 203 struct ip_vs_conn *cp;
194 204
195 hash = ip_vs_conn_hashkey(protocol, s_addr, s_port); 205 hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
196 206
197 ct_read_lock(hash); 207 ct_read_lock(hash);
198 208
199 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { 209 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
200 if (s_addr==cp->caddr && s_port==cp->cport && 210 if (cp->af == af &&
201 d_port==cp->vport && d_addr==cp->vaddr && 211 ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
212 ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
213 s_port == cp->cport && d_port == cp->vport &&
202 ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) && 214 ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
203 protocol==cp->protocol) { 215 protocol == cp->protocol) {
204 /* HIT */ 216 /* HIT */
205 atomic_inc(&cp->refcnt); 217 atomic_inc(&cp->refcnt);
206 ct_read_unlock(hash); 218 ct_read_unlock(hash);
@@ -214,39 +226,44 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
214} 226}
215 227
216struct ip_vs_conn *ip_vs_conn_in_get 228struct ip_vs_conn *ip_vs_conn_in_get
217(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port) 229(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
230 const union nf_inet_addr *d_addr, __be16 d_port)
218{ 231{
219 struct ip_vs_conn *cp; 232 struct ip_vs_conn *cp;
220 233
221 cp = __ip_vs_conn_in_get(protocol, s_addr, s_port, d_addr, d_port); 234 cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
222 if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) 235 if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
223 cp = __ip_vs_conn_in_get(protocol, s_addr, 0, d_addr, d_port); 236 cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
237 d_port);
224 238
225 IP_VS_DBG(9, "lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n", 239 IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
226 ip_vs_proto_name(protocol), 240 ip_vs_proto_name(protocol),
227 NIPQUAD(s_addr), ntohs(s_port), 241 IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
228 NIPQUAD(d_addr), ntohs(d_port), 242 IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
229 cp?"hit":"not hit"); 243 cp ? "hit" : "not hit");
230 244
231 return cp; 245 return cp;
232} 246}
233 247
234/* Get reference to connection template */ 248/* Get reference to connection template */
235struct ip_vs_conn *ip_vs_ct_in_get 249struct ip_vs_conn *ip_vs_ct_in_get
236(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port) 250(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
251 const union nf_inet_addr *d_addr, __be16 d_port)
237{ 252{
238 unsigned hash; 253 unsigned hash;
239 struct ip_vs_conn *cp; 254 struct ip_vs_conn *cp;
240 255
241 hash = ip_vs_conn_hashkey(protocol, s_addr, s_port); 256 hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
242 257
243 ct_read_lock(hash); 258 ct_read_lock(hash);
244 259
245 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { 260 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
246 if (s_addr==cp->caddr && s_port==cp->cport && 261 if (cp->af == af &&
247 d_port==cp->vport && d_addr==cp->vaddr && 262 ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
263 ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
264 s_port == cp->cport && d_port == cp->vport &&
248 cp->flags & IP_VS_CONN_F_TEMPLATE && 265 cp->flags & IP_VS_CONN_F_TEMPLATE &&
249 protocol==cp->protocol) { 266 protocol == cp->protocol) {
250 /* HIT */ 267 /* HIT */
251 atomic_inc(&cp->refcnt); 268 atomic_inc(&cp->refcnt);
252 goto out; 269 goto out;
@@ -257,11 +274,11 @@ struct ip_vs_conn *ip_vs_ct_in_get
257 out: 274 out:
258 ct_read_unlock(hash); 275 ct_read_unlock(hash);
259 276
260 IP_VS_DBG(9, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n", 277 IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
261 ip_vs_proto_name(protocol), 278 ip_vs_proto_name(protocol),
262 NIPQUAD(s_addr), ntohs(s_port), 279 IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
263 NIPQUAD(d_addr), ntohs(d_port), 280 IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
264 cp?"hit":"not hit"); 281 cp ? "hit" : "not hit");
265 282
266 return cp; 283 return cp;
267} 284}
@@ -273,7 +290,8 @@ struct ip_vs_conn *ip_vs_ct_in_get
273 * d_addr, d_port: pkt dest address (foreign host) 290 * d_addr, d_port: pkt dest address (foreign host)
274 */ 291 */
275struct ip_vs_conn *ip_vs_conn_out_get 292struct ip_vs_conn *ip_vs_conn_out_get
276(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port) 293(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
294 const union nf_inet_addr *d_addr, __be16 d_port)
277{ 295{
278 unsigned hash; 296 unsigned hash;
279 struct ip_vs_conn *cp, *ret=NULL; 297 struct ip_vs_conn *cp, *ret=NULL;
@@ -281,13 +299,15 @@ struct ip_vs_conn *ip_vs_conn_out_get
281 /* 299 /*
282 * Check for "full" addressed entries 300 * Check for "full" addressed entries
283 */ 301 */
284 hash = ip_vs_conn_hashkey(protocol, d_addr, d_port); 302 hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
285 303
286 ct_read_lock(hash); 304 ct_read_lock(hash);
287 305
288 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { 306 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
289 if (d_addr == cp->caddr && d_port == cp->cport && 307 if (cp->af == af &&
290 s_port == cp->dport && s_addr == cp->daddr && 308 ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
309 ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
310 d_port == cp->cport && s_port == cp->dport &&
291 protocol == cp->protocol) { 311 protocol == cp->protocol) {
292 /* HIT */ 312 /* HIT */
293 atomic_inc(&cp->refcnt); 313 atomic_inc(&cp->refcnt);
@@ -298,11 +318,11 @@ struct ip_vs_conn *ip_vs_conn_out_get
298 318
299 ct_read_unlock(hash); 319 ct_read_unlock(hash);
300 320
301 IP_VS_DBG(9, "lookup/out %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n", 321 IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
302 ip_vs_proto_name(protocol), 322 ip_vs_proto_name(protocol),
303 NIPQUAD(s_addr), ntohs(s_port), 323 IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
304 NIPQUAD(d_addr), ntohs(d_port), 324 IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
305 ret?"hit":"not hit"); 325 ret ? "hit" : "not hit");
306 326
307 return ret; 327 return ret;
308} 328}
@@ -369,6 +389,33 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
369 } 389 }
370} 390}
371 391
392#ifdef CONFIG_IP_VS_IPV6
393static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
394{
395 switch (IP_VS_FWD_METHOD(cp)) {
396 case IP_VS_CONN_F_MASQ:
397 cp->packet_xmit = ip_vs_nat_xmit_v6;
398 break;
399
400 case IP_VS_CONN_F_TUNNEL:
401 cp->packet_xmit = ip_vs_tunnel_xmit_v6;
402 break;
403
404 case IP_VS_CONN_F_DROUTE:
405 cp->packet_xmit = ip_vs_dr_xmit_v6;
406 break;
407
408 case IP_VS_CONN_F_LOCALNODE:
409 cp->packet_xmit = ip_vs_null_xmit;
410 break;
411
412 case IP_VS_CONN_F_BYPASS:
413 cp->packet_xmit = ip_vs_bypass_xmit_v6;
414 break;
415 }
416}
417#endif
418
372 419
373static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest) 420static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
374{ 421{
@@ -402,16 +449,16 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
402 cp->flags |= atomic_read(&dest->conn_flags); 449 cp->flags |= atomic_read(&dest->conn_flags);
403 cp->dest = dest; 450 cp->dest = dest;
404 451
405 IP_VS_DBG(7, "Bind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d " 452 IP_VS_DBG_BUF(7, "Bind-dest %s c:%s:%d v:%s:%d "
406 "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d " 453 "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
407 "dest->refcnt:%d\n", 454 "dest->refcnt:%d\n",
408 ip_vs_proto_name(cp->protocol), 455 ip_vs_proto_name(cp->protocol),
409 NIPQUAD(cp->caddr), ntohs(cp->cport), 456 IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
410 NIPQUAD(cp->vaddr), ntohs(cp->vport), 457 IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
411 NIPQUAD(cp->daddr), ntohs(cp->dport), 458 IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
412 ip_vs_fwd_tag(cp), cp->state, 459 ip_vs_fwd_tag(cp), cp->state,
413 cp->flags, atomic_read(&cp->refcnt), 460 cp->flags, atomic_read(&cp->refcnt),
414 atomic_read(&dest->refcnt)); 461 atomic_read(&dest->refcnt));
415 462
416 /* Update the connection counters */ 463 /* Update the connection counters */
417 if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { 464 if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -444,8 +491,9 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
444 struct ip_vs_dest *dest; 491 struct ip_vs_dest *dest;
445 492
446 if ((cp) && (!cp->dest)) { 493 if ((cp) && (!cp->dest)) {
447 dest = ip_vs_find_dest(cp->daddr, cp->dport, 494 dest = ip_vs_find_dest(cp->af, &cp->daddr, cp->dport,
448 cp->vaddr, cp->vport, cp->protocol); 495 &cp->vaddr, cp->vport,
496 cp->protocol);
449 ip_vs_bind_dest(cp, dest); 497 ip_vs_bind_dest(cp, dest);
450 return dest; 498 return dest;
451 } else 499 } else
@@ -464,16 +512,16 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
464 if (!dest) 512 if (!dest)
465 return; 513 return;
466 514
467 IP_VS_DBG(7, "Unbind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d " 515 IP_VS_DBG_BUF(7, "Unbind-dest %s c:%s:%d v:%s:%d "
468 "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d " 516 "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
469 "dest->refcnt:%d\n", 517 "dest->refcnt:%d\n",
470 ip_vs_proto_name(cp->protocol), 518 ip_vs_proto_name(cp->protocol),
471 NIPQUAD(cp->caddr), ntohs(cp->cport), 519 IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
472 NIPQUAD(cp->vaddr), ntohs(cp->vport), 520 IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
473 NIPQUAD(cp->daddr), ntohs(cp->dport), 521 IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
474 ip_vs_fwd_tag(cp), cp->state, 522 ip_vs_fwd_tag(cp), cp->state,
475 cp->flags, atomic_read(&cp->refcnt), 523 cp->flags, atomic_read(&cp->refcnt),
476 atomic_read(&dest->refcnt)); 524 atomic_read(&dest->refcnt));
477 525
478 /* Update the connection counters */ 526 /* Update the connection counters */
479 if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { 527 if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -526,13 +574,16 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
526 !(dest->flags & IP_VS_DEST_F_AVAILABLE) || 574 !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
527 (sysctl_ip_vs_expire_quiescent_template && 575 (sysctl_ip_vs_expire_quiescent_template &&
528 (atomic_read(&dest->weight) == 0))) { 576 (atomic_read(&dest->weight) == 0))) {
529 IP_VS_DBG(9, "check_template: dest not available for " 577 IP_VS_DBG_BUF(9, "check_template: dest not available for "
530 "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d " 578 "protocol %s s:%s:%d v:%s:%d "
531 "-> d:%u.%u.%u.%u:%d\n", 579 "-> d:%s:%d\n",
532 ip_vs_proto_name(ct->protocol), 580 ip_vs_proto_name(ct->protocol),
533 NIPQUAD(ct->caddr), ntohs(ct->cport), 581 IP_VS_DBG_ADDR(ct->af, &ct->caddr),
534 NIPQUAD(ct->vaddr), ntohs(ct->vport), 582 ntohs(ct->cport),
535 NIPQUAD(ct->daddr), ntohs(ct->dport)); 583 IP_VS_DBG_ADDR(ct->af, &ct->vaddr),
584 ntohs(ct->vport),
585 IP_VS_DBG_ADDR(ct->af, &ct->daddr),
586 ntohs(ct->dport));
536 587
537 /* 588 /*
538 * Invalidate the connection template 589 * Invalidate the connection template
@@ -625,8 +676,9 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
625 * Create a new connection entry and hash it into the ip_vs_conn_tab 676 * Create a new connection entry and hash it into the ip_vs_conn_tab
626 */ 677 */
627struct ip_vs_conn * 678struct ip_vs_conn *
628ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport, 679ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
629 __be32 daddr, __be16 dport, unsigned flags, 680 const union nf_inet_addr *vaddr, __be16 vport,
681 const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
630 struct ip_vs_dest *dest) 682 struct ip_vs_dest *dest)
631{ 683{
632 struct ip_vs_conn *cp; 684 struct ip_vs_conn *cp;
@@ -640,12 +692,13 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
640 692
641 INIT_LIST_HEAD(&cp->c_list); 693 INIT_LIST_HEAD(&cp->c_list);
642 setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp); 694 setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
695 cp->af = af;
643 cp->protocol = proto; 696 cp->protocol = proto;
644 cp->caddr = caddr; 697 ip_vs_addr_copy(af, &cp->caddr, caddr);
645 cp->cport = cport; 698 cp->cport = cport;
646 cp->vaddr = vaddr; 699 ip_vs_addr_copy(af, &cp->vaddr, vaddr);
647 cp->vport = vport; 700 cp->vport = vport;
648 cp->daddr = daddr; 701 ip_vs_addr_copy(af, &cp->daddr, daddr);
649 cp->dport = dport; 702 cp->dport = dport;
650 cp->flags = flags; 703 cp->flags = flags;
651 spin_lock_init(&cp->lock); 704 spin_lock_init(&cp->lock);
@@ -672,7 +725,12 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
672 cp->timeout = 3*HZ; 725 cp->timeout = 3*HZ;
673 726
674 /* Bind its packet transmitter */ 727 /* Bind its packet transmitter */
675 ip_vs_bind_xmit(cp); 728#ifdef CONFIG_IP_VS_IPV6
729 if (af == AF_INET6)
730 ip_vs_bind_xmit_v6(cp);
731 else
732#endif
733 ip_vs_bind_xmit(cp);
676 734
677 if (unlikely(pp && atomic_read(&pp->appcnt))) 735 if (unlikely(pp && atomic_read(&pp->appcnt)))
678 ip_vs_bind_app(cp, pp); 736 ip_vs_bind_app(cp, pp);
@@ -760,12 +818,26 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
760 else { 818 else {
761 const struct ip_vs_conn *cp = v; 819 const struct ip_vs_conn *cp = v;
762 820
763 seq_printf(seq, 821#ifdef CONFIG_IP_VS_IPV6
764 "%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n", 822 if (cp->af == AF_INET6)
823 seq_printf(seq,
824 "%-3s " NIP6_FMT " %04X " NIP6_FMT
825 " %04X " NIP6_FMT " %04X %-11s %7lu\n",
826 ip_vs_proto_name(cp->protocol),
827 NIP6(cp->caddr.in6), ntohs(cp->cport),
828 NIP6(cp->vaddr.in6), ntohs(cp->vport),
829 NIP6(cp->daddr.in6), ntohs(cp->dport),
830 ip_vs_state_name(cp->protocol, cp->state),
831 (cp->timer.expires-jiffies)/HZ);
832 else
833#endif
834 seq_printf(seq,
835 "%-3s %08X %04X %08X %04X"
836 " %08X %04X %-11s %7lu\n",
765 ip_vs_proto_name(cp->protocol), 837 ip_vs_proto_name(cp->protocol),
766 ntohl(cp->caddr), ntohs(cp->cport), 838 ntohl(cp->caddr.ip), ntohs(cp->cport),
767 ntohl(cp->vaddr), ntohs(cp->vport), 839 ntohl(cp->vaddr.ip), ntohs(cp->vport),
768 ntohl(cp->daddr), ntohs(cp->dport), 840 ntohl(cp->daddr.ip), ntohs(cp->dport),
769 ip_vs_state_name(cp->protocol, cp->state), 841 ip_vs_state_name(cp->protocol, cp->state),
770 (cp->timer.expires-jiffies)/HZ); 842 (cp->timer.expires-jiffies)/HZ);
771 } 843 }
@@ -809,12 +881,27 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
809 else { 881 else {
810 const struct ip_vs_conn *cp = v; 882 const struct ip_vs_conn *cp = v;
811 883
812 seq_printf(seq, 884#ifdef CONFIG_IP_VS_IPV6
813 "%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n", 885 if (cp->af == AF_INET6)
886 seq_printf(seq,
887 "%-3s " NIP6_FMT " %04X " NIP6_FMT
888 " %04X " NIP6_FMT " %04X %-11s %-6s %7lu\n",
889 ip_vs_proto_name(cp->protocol),
890 NIP6(cp->caddr.in6), ntohs(cp->cport),
891 NIP6(cp->vaddr.in6), ntohs(cp->vport),
892 NIP6(cp->daddr.in6), ntohs(cp->dport),
893 ip_vs_state_name(cp->protocol, cp->state),
894 ip_vs_origin_name(cp->flags),
895 (cp->timer.expires-jiffies)/HZ);
896 else
897#endif
898 seq_printf(seq,
899 "%-3s %08X %04X %08X %04X "
900 "%08X %04X %-11s %-6s %7lu\n",
814 ip_vs_proto_name(cp->protocol), 901 ip_vs_proto_name(cp->protocol),
815 ntohl(cp->caddr), ntohs(cp->cport), 902 ntohl(cp->caddr.ip), ntohs(cp->cport),
816 ntohl(cp->vaddr), ntohs(cp->vport), 903 ntohl(cp->vaddr.ip), ntohs(cp->vport),
817 ntohl(cp->daddr), ntohs(cp->dport), 904 ntohl(cp->daddr.ip), ntohs(cp->dport),
818 ip_vs_state_name(cp->protocol, cp->state), 905 ip_vs_state_name(cp->protocol, cp->state),
819 ip_vs_origin_name(cp->flags), 906 ip_vs_origin_name(cp->flags),
820 (cp->timer.expires-jiffies)/HZ); 907 (cp->timer.expires-jiffies)/HZ);
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 9fbf0a6d7392..80a4fcf33a54 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;
@@ -92,18 +102,18 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
92 struct ip_vs_dest *dest = cp->dest; 102 struct ip_vs_dest *dest = cp->dest;
93 if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) { 103 if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
94 spin_lock(&dest->stats.lock); 104 spin_lock(&dest->stats.lock);
95 dest->stats.inpkts++; 105 dest->stats.ustats.inpkts++;
96 dest->stats.inbytes += skb->len; 106 dest->stats.ustats.inbytes += skb->len;
97 spin_unlock(&dest->stats.lock); 107 spin_unlock(&dest->stats.lock);
98 108
99 spin_lock(&dest->svc->stats.lock); 109 spin_lock(&dest->svc->stats.lock);
100 dest->svc->stats.inpkts++; 110 dest->svc->stats.ustats.inpkts++;
101 dest->svc->stats.inbytes += skb->len; 111 dest->svc->stats.ustats.inbytes += skb->len;
102 spin_unlock(&dest->svc->stats.lock); 112 spin_unlock(&dest->svc->stats.lock);
103 113
104 spin_lock(&ip_vs_stats.lock); 114 spin_lock(&ip_vs_stats.lock);
105 ip_vs_stats.inpkts++; 115 ip_vs_stats.ustats.inpkts++;
106 ip_vs_stats.inbytes += skb->len; 116 ip_vs_stats.ustats.inbytes += skb->len;
107 spin_unlock(&ip_vs_stats.lock); 117 spin_unlock(&ip_vs_stats.lock);
108 } 118 }
109} 119}
@@ -115,18 +125,18 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
115 struct ip_vs_dest *dest = cp->dest; 125 struct ip_vs_dest *dest = cp->dest;
116 if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) { 126 if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
117 spin_lock(&dest->stats.lock); 127 spin_lock(&dest->stats.lock);
118 dest->stats.outpkts++; 128 dest->stats.ustats.outpkts++;
119 dest->stats.outbytes += skb->len; 129 dest->stats.ustats.outbytes += skb->len;
120 spin_unlock(&dest->stats.lock); 130 spin_unlock(&dest->stats.lock);
121 131
122 spin_lock(&dest->svc->stats.lock); 132 spin_lock(&dest->svc->stats.lock);
123 dest->svc->stats.outpkts++; 133 dest->svc->stats.ustats.outpkts++;
124 dest->svc->stats.outbytes += skb->len; 134 dest->svc->stats.ustats.outbytes += skb->len;
125 spin_unlock(&dest->svc->stats.lock); 135 spin_unlock(&dest->svc->stats.lock);
126 136
127 spin_lock(&ip_vs_stats.lock); 137 spin_lock(&ip_vs_stats.lock);
128 ip_vs_stats.outpkts++; 138 ip_vs_stats.ustats.outpkts++;
129 ip_vs_stats.outbytes += skb->len; 139 ip_vs_stats.ustats.outbytes += skb->len;
130 spin_unlock(&ip_vs_stats.lock); 140 spin_unlock(&ip_vs_stats.lock);
131 } 141 }
132} 142}
@@ -136,15 +146,15 @@ static inline void
136ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc) 146ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
137{ 147{
138 spin_lock(&cp->dest->stats.lock); 148 spin_lock(&cp->dest->stats.lock);
139 cp->dest->stats.conns++; 149 cp->dest->stats.ustats.conns++;
140 spin_unlock(&cp->dest->stats.lock); 150 spin_unlock(&cp->dest->stats.lock);
141 151
142 spin_lock(&svc->stats.lock); 152 spin_lock(&svc->stats.lock);
143 svc->stats.conns++; 153 svc->stats.ustats.conns++;
144 spin_unlock(&svc->stats.lock); 154 spin_unlock(&svc->stats.lock);
145 155
146 spin_lock(&ip_vs_stats.lock); 156 spin_lock(&ip_vs_stats.lock);
147 ip_vs_stats.conns++; 157 ip_vs_stats.ustats.conns++;
148 spin_unlock(&ip_vs_stats.lock); 158 spin_unlock(&ip_vs_stats.lock);
149} 159}
150 160
@@ -173,20 +183,28 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
173 __be16 ports[2]) 183 __be16 ports[2])
174{ 184{
175 struct ip_vs_conn *cp = NULL; 185 struct ip_vs_conn *cp = NULL;
176 struct iphdr *iph = ip_hdr(skb); 186 struct ip_vs_iphdr iph;
177 struct ip_vs_dest *dest; 187 struct ip_vs_dest *dest;
178 struct ip_vs_conn *ct; 188 struct ip_vs_conn *ct;
179 __be16 dport; /* destination port to forward */ 189 __be16 dport; /* destination port to forward */
180 __be32 snet; /* source network of the client, after masking */ 190 union nf_inet_addr snet; /* source network of the client,
191 after masking */
192
193 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
181 194
182 /* Mask saddr with the netmask to adjust template granularity */ 195 /* Mask saddr with the netmask to adjust template granularity */
183 snet = iph->saddr & svc->netmask; 196#ifdef CONFIG_IP_VS_IPV6
197 if (svc->af == AF_INET6)
198 ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask);
199 else
200#endif
201 snet.ip = iph.saddr.ip & svc->netmask;
184 202
185 IP_VS_DBG(6, "p-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u " 203 IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
186 "mnet %u.%u.%u.%u\n", 204 "mnet %s\n",
187 NIPQUAD(iph->saddr), ntohs(ports[0]), 205 IP_VS_DBG_ADDR(svc->af, &iph.saddr), ntohs(ports[0]),
188 NIPQUAD(iph->daddr), ntohs(ports[1]), 206 IP_VS_DBG_ADDR(svc->af, &iph.daddr), ntohs(ports[1]),
189 NIPQUAD(snet)); 207 IP_VS_DBG_ADDR(svc->af, &snet));
190 208
191 /* 209 /*
192 * As far as we know, FTP is a very complicated network protocol, and 210 * As far as we know, FTP is a very complicated network protocol, and
@@ -204,11 +222,11 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
204 if (ports[1] == svc->port) { 222 if (ports[1] == svc->port) {
205 /* Check if a template already exists */ 223 /* Check if a template already exists */
206 if (svc->port != FTPPORT) 224 if (svc->port != FTPPORT)
207 ct = ip_vs_ct_in_get(iph->protocol, snet, 0, 225 ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
208 iph->daddr, ports[1]); 226 &iph.daddr, ports[1]);
209 else 227 else
210 ct = ip_vs_ct_in_get(iph->protocol, snet, 0, 228 ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
211 iph->daddr, 0); 229 &iph.daddr, 0);
212 230
213 if (!ct || !ip_vs_check_template(ct)) { 231 if (!ct || !ip_vs_check_template(ct)) {
214 /* 232 /*
@@ -228,18 +246,18 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
228 * for ftp service. 246 * for ftp service.
229 */ 247 */
230 if (svc->port != FTPPORT) 248 if (svc->port != FTPPORT)
231 ct = ip_vs_conn_new(iph->protocol, 249 ct = ip_vs_conn_new(svc->af, iph.protocol,
232 snet, 0, 250 &snet, 0,
233 iph->daddr, 251 &iph.daddr,
234 ports[1], 252 ports[1],
235 dest->addr, dest->port, 253 &dest->addr, dest->port,
236 IP_VS_CONN_F_TEMPLATE, 254 IP_VS_CONN_F_TEMPLATE,
237 dest); 255 dest);
238 else 256 else
239 ct = ip_vs_conn_new(iph->protocol, 257 ct = ip_vs_conn_new(svc->af, iph.protocol,
240 snet, 0, 258 &snet, 0,
241 iph->daddr, 0, 259 &iph.daddr, 0,
242 dest->addr, 0, 260 &dest->addr, 0,
243 IP_VS_CONN_F_TEMPLATE, 261 IP_VS_CONN_F_TEMPLATE,
244 dest); 262 dest);
245 if (ct == NULL) 263 if (ct == NULL)
@@ -258,12 +276,16 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
258 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0> 276 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
259 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0> 277 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
260 */ 278 */
261 if (svc->fwmark) 279 if (svc->fwmark) {
262 ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0, 280 union nf_inet_addr fwmark = {
263 htonl(svc->fwmark), 0); 281 .all = { 0, 0, 0, htonl(svc->fwmark) }
264 else 282 };
265 ct = ip_vs_ct_in_get(iph->protocol, snet, 0, 283
266 iph->daddr, 0); 284 ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
285 &fwmark, 0);
286 } else
287 ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
288 &iph.daddr, 0);
267 289
268 if (!ct || !ip_vs_check_template(ct)) { 290 if (!ct || !ip_vs_check_template(ct)) {
269 /* 291 /*
@@ -282,18 +304,22 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
282 /* 304 /*
283 * Create a template according to the service 305 * Create a template according to the service
284 */ 306 */
285 if (svc->fwmark) 307 if (svc->fwmark) {
286 ct = ip_vs_conn_new(IPPROTO_IP, 308 union nf_inet_addr fwmark = {
287 snet, 0, 309 .all = { 0, 0, 0, htonl(svc->fwmark) }
288 htonl(svc->fwmark), 0, 310 };
289 dest->addr, 0, 311
312 ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
313 &snet, 0,
314 &fwmark, 0,
315 &dest->addr, 0,
290 IP_VS_CONN_F_TEMPLATE, 316 IP_VS_CONN_F_TEMPLATE,
291 dest); 317 dest);
292 else 318 } else
293 ct = ip_vs_conn_new(iph->protocol, 319 ct = ip_vs_conn_new(svc->af, iph.protocol,
294 snet, 0, 320 &snet, 0,
295 iph->daddr, 0, 321 &iph.daddr, 0,
296 dest->addr, 0, 322 &dest->addr, 0,
297 IP_VS_CONN_F_TEMPLATE, 323 IP_VS_CONN_F_TEMPLATE,
298 dest); 324 dest);
299 if (ct == NULL) 325 if (ct == NULL)
@@ -310,10 +336,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
310 /* 336 /*
311 * Create a new connection according to the template 337 * Create a new connection according to the template
312 */ 338 */
313 cp = ip_vs_conn_new(iph->protocol, 339 cp = ip_vs_conn_new(svc->af, iph.protocol,
314 iph->saddr, ports[0], 340 &iph.saddr, ports[0],
315 iph->daddr, ports[1], 341 &iph.daddr, ports[1],
316 dest->addr, dport, 342 &dest->addr, dport,
317 0, 343 0,
318 dest); 344 dest);
319 if (cp == NULL) { 345 if (cp == NULL) {
@@ -342,12 +368,12 @@ struct ip_vs_conn *
342ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) 368ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
343{ 369{
344 struct ip_vs_conn *cp = NULL; 370 struct ip_vs_conn *cp = NULL;
345 struct iphdr *iph = ip_hdr(skb); 371 struct ip_vs_iphdr iph;
346 struct ip_vs_dest *dest; 372 struct ip_vs_dest *dest;
347 __be16 _ports[2], *pptr; 373 __be16 _ports[2], *pptr;
348 374
349 pptr = skb_header_pointer(skb, iph->ihl*4, 375 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
350 sizeof(_ports), _ports); 376 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
351 if (pptr == NULL) 377 if (pptr == NULL)
352 return NULL; 378 return NULL;
353 379
@@ -377,22 +403,22 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
377 /* 403 /*
378 * Create a connection entry. 404 * Create a connection entry.
379 */ 405 */
380 cp = ip_vs_conn_new(iph->protocol, 406 cp = ip_vs_conn_new(svc->af, iph.protocol,
381 iph->saddr, pptr[0], 407 &iph.saddr, pptr[0],
382 iph->daddr, pptr[1], 408 &iph.daddr, pptr[1],
383 dest->addr, dest->port?dest->port:pptr[1], 409 &dest->addr, dest->port ? dest->port : pptr[1],
384 0, 410 0,
385 dest); 411 dest);
386 if (cp == NULL) 412 if (cp == NULL)
387 return NULL; 413 return NULL;
388 414
389 IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u " 415 IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
390 "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n", 416 "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
391 ip_vs_fwd_tag(cp), 417 ip_vs_fwd_tag(cp),
392 NIPQUAD(cp->caddr), ntohs(cp->cport), 418 IP_VS_DBG_ADDR(svc->af, &cp->caddr), ntohs(cp->cport),
393 NIPQUAD(cp->vaddr), ntohs(cp->vport), 419 IP_VS_DBG_ADDR(svc->af, &cp->vaddr), ntohs(cp->vport),
394 NIPQUAD(cp->daddr), ntohs(cp->dport), 420 IP_VS_DBG_ADDR(svc->af, &cp->daddr), ntohs(cp->dport),
395 cp->flags, atomic_read(&cp->refcnt)); 421 cp->flags, atomic_read(&cp->refcnt));
396 422
397 ip_vs_conn_stats(cp, svc); 423 ip_vs_conn_stats(cp, svc);
398 return cp; 424 return cp;
@@ -408,20 +434,27 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
408 struct ip_vs_protocol *pp) 434 struct ip_vs_protocol *pp)
409{ 435{
410 __be16 _ports[2], *pptr; 436 __be16 _ports[2], *pptr;
411 struct iphdr *iph = ip_hdr(skb); 437 struct ip_vs_iphdr iph;
438 int unicast;
439 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
412 440
413 pptr = skb_header_pointer(skb, iph->ihl*4, 441 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
414 sizeof(_ports), _ports);
415 if (pptr == NULL) { 442 if (pptr == NULL) {
416 ip_vs_service_put(svc); 443 ip_vs_service_put(svc);
417 return NF_DROP; 444 return NF_DROP;
418 } 445 }
419 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
420 /* 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
421 and the destination is RTN_UNICAST (and not local), then create 455 and the destination is a non-local unicast, then create
422 a cache_bypass connection entry */ 456 a cache_bypass connection entry */
423 if (sysctl_ip_vs_cache_bypass && svc->fwmark 457 if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
424 && (inet_addr_type(&init_net, iph->daddr) == RTN_UNICAST)) {
425 int ret, cs; 458 int ret, cs;
426 struct ip_vs_conn *cp; 459 struct ip_vs_conn *cp;
427 460
@@ -429,9 +462,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
429 462
430 /* create a new connection entry */ 463 /* create a new connection entry */
431 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");
432 cp = ip_vs_conn_new(iph->protocol, 465 cp = ip_vs_conn_new(svc->af, iph.protocol,
433 iph->saddr, pptr[0], 466 &iph.saddr, pptr[0],
434 iph->daddr, pptr[1], 467 &iph.daddr, pptr[1],
435 0, 0, 468 0, 0,
436 IP_VS_CONN_F_BYPASS, 469 IP_VS_CONN_F_BYPASS,
437 NULL); 470 NULL);
@@ -473,7 +506,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
473 * created, the TCP RST packet cannot be sent, instead that 506 * created, the TCP RST packet cannot be sent, instead that
474 * 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
475 */ 508 */
476 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
477 return NF_DROP; 517 return NF_DROP;
478} 518}
479 519
@@ -512,6 +552,14 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
512 return err; 552 return err;
513} 553}
514 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
515/* 563/*
516 * Packet has been made sufficiently writable in caller 564 * Packet has been made sufficiently writable in caller
517 * - inout: 1=in->out, 0=out->in 565 * - inout: 1=in->out, 0=out->in
@@ -526,14 +574,14 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
526 struct iphdr *ciph = (struct iphdr *)(icmph + 1); 574 struct iphdr *ciph = (struct iphdr *)(icmph + 1);
527 575
528 if (inout) { 576 if (inout) {
529 iph->saddr = cp->vaddr; 577 iph->saddr = cp->vaddr.ip;
530 ip_send_check(iph); 578 ip_send_check(iph);
531 ciph->daddr = cp->vaddr; 579 ciph->daddr = cp->vaddr.ip;
532 ip_send_check(ciph); 580 ip_send_check(ciph);
533 } else { 581 } else {
534 iph->daddr = cp->daddr; 582 iph->daddr = cp->daddr.ip;
535 ip_send_check(iph); 583 ip_send_check(iph);
536 ciph->saddr = cp->daddr; 584 ciph->saddr = cp->daddr.ip;
537 ip_send_check(ciph); 585 ip_send_check(ciph);
538 } 586 }
539 587
@@ -560,21 +608,112 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
560 "Forwarding altered incoming ICMP"); 608 "Forwarding altered incoming ICMP");
561} 609}
562 610
611#ifdef CONFIG_IP_VS_IPV6
612void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
613 struct ip_vs_conn *cp, int inout)
614{
615 struct ipv6hdr *iph = ipv6_hdr(skb);
616 unsigned int icmp_offset = sizeof(struct ipv6hdr);
617 struct icmp6hdr *icmph = (struct icmp6hdr *)(skb_network_header(skb) +
618 icmp_offset);
619 struct ipv6hdr *ciph = (struct ipv6hdr *)(icmph + 1);
620
621 if (inout) {
622 iph->saddr = cp->vaddr.in6;
623 ciph->daddr = cp->vaddr.in6;
624 } else {
625 iph->daddr = cp->daddr.in6;
626 ciph->saddr = cp->daddr.in6;
627 }
628
629 /* the TCP/UDP port */
630 if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr) {
631 __be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
632
633 if (inout)
634 ports[1] = cp->vport;
635 else
636 ports[0] = cp->dport;
637 }
638
639 /* And finally the ICMP checksum */
640 icmph->icmp6_cksum = 0;
641 /* TODO IPv6: is this correct for ICMPv6? */
642 ip_vs_checksum_complete(skb, icmp_offset);
643 skb->ip_summed = CHECKSUM_UNNECESSARY;
644
645 if (inout)
646 IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
647 "Forwarding altered outgoing ICMPv6");
648 else
649 IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
650 "Forwarding altered incoming ICMPv6");
651}
652#endif
653
654/* Handle relevant response ICMP messages - forward to the right
655 * destination host. Used for NAT and local client.
656 */
657static int handle_response_icmp(int af, struct sk_buff *skb,
658 union nf_inet_addr *snet,
659 __u8 protocol, struct ip_vs_conn *cp,
660 struct ip_vs_protocol *pp,
661 unsigned int offset, unsigned int ihl)
662{
663 unsigned int verdict = NF_DROP;
664
665 if (IP_VS_FWD_METHOD(cp) != 0) {
666 IP_VS_ERR("shouldn't reach here, because the box is on the "
667 "half connection in the tun/dr module.\n");
668 }
669
670 /* Ensure the checksum is correct */
671 if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
672 /* Failed checksum! */
673 IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
674 IP_VS_DBG_ADDR(af, snet));
675 goto out;
676 }
677
678 if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol)
679 offset += 2 * sizeof(__u16);
680 if (!skb_make_writable(skb, offset))
681 goto out;
682
683#ifdef CONFIG_IP_VS_IPV6
684 if (af == AF_INET6)
685 ip_vs_nat_icmp_v6(skb, pp, cp, 1);
686 else
687#endif
688 ip_vs_nat_icmp(skb, pp, cp, 1);
689
690 /* do the statistics and put it back */
691 ip_vs_out_stats(cp, skb);
692
693 skb->ipvs_property = 1;
694 verdict = NF_ACCEPT;
695
696out:
697 __ip_vs_conn_put(cp);
698
699 return verdict;
700}
701
563/* 702/*
564 * Handle ICMP messages in the inside-to-outside direction (outgoing). 703 * Handle ICMP messages in the inside-to-outside direction (outgoing).
565 * Find any that might be relevant, check against existing connections, 704 * Find any that might be relevant, check against existing connections.
566 * forward to the right destination host if relevant.
567 * Currently handles error types - unreachable, quench, ttl exceeded. 705 * Currently handles error types - unreachable, quench, ttl exceeded.
568 * (Only used in VS/NAT)
569 */ 706 */
570static int ip_vs_out_icmp(struct sk_buff *skb, int *related) 707static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
571{ 708{
572 struct iphdr *iph; 709 struct iphdr *iph;
573 struct icmphdr _icmph, *ic; 710 struct icmphdr _icmph, *ic;
574 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ 711 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
712 struct ip_vs_iphdr ciph;
575 struct ip_vs_conn *cp; 713 struct ip_vs_conn *cp;
576 struct ip_vs_protocol *pp; 714 struct ip_vs_protocol *pp;
577 unsigned int offset, ihl, verdict; 715 unsigned int offset, ihl;
716 union nf_inet_addr snet;
578 717
579 *related = 1; 718 *related = 1;
580 719
@@ -627,102 +766,231 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
627 766
628 offset += cih->ihl * 4; 767 offset += cih->ihl * 4;
629 768
769 ip_vs_fill_iphdr(AF_INET, cih, &ciph);
630 /* The embedded headers contain source and dest in reverse order */ 770 /* The embedded headers contain source and dest in reverse order */
631 cp = pp->conn_out_get(skb, pp, cih, offset, 1); 771 cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
632 if (!cp) 772 if (!cp)
633 return NF_ACCEPT; 773 return NF_ACCEPT;
634 774
635 verdict = NF_DROP; 775 snet.ip = iph->saddr;
776 return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp,
777 pp, offset, ihl);
778}
636 779
637 if (IP_VS_FWD_METHOD(cp) != 0) { 780#ifdef CONFIG_IP_VS_IPV6
638 IP_VS_ERR("shouldn't reach here, because the box is on the " 781static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
639 "half connection in the tun/dr module.\n"); 782{
783 struct ipv6hdr *iph;
784 struct icmp6hdr _icmph, *ic;
785 struct ipv6hdr _ciph, *cih; /* The ip header contained
786 within the ICMP */
787 struct ip_vs_iphdr ciph;
788 struct ip_vs_conn *cp;
789 struct ip_vs_protocol *pp;
790 unsigned int offset;
791 union nf_inet_addr snet;
792
793 *related = 1;
794
795 /* reassemble IP fragments */
796 if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
797 if (ip_vs_gather_frags_v6(skb, IP_DEFRAG_VS_OUT))
798 return NF_STOLEN;
640 } 799 }
641 800
642 /* Ensure the checksum is correct */ 801 iph = ipv6_hdr(skb);
643 if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) { 802 offset = sizeof(struct ipv6hdr);
644 /* Failed checksum! */ 803 ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
645 IP_VS_DBG(1, "Forward ICMP: failed checksum from %d.%d.%d.%d!\n", 804 if (ic == NULL)
646 NIPQUAD(iph->saddr)); 805 return NF_DROP;
647 goto out; 806
807 IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
808 ic->icmp6_type, ntohs(icmpv6_id(ic)),
809 NIP6(iph->saddr), NIP6(iph->daddr));
810
811 /*
812 * Work through seeing if this is for us.
813 * These checks are supposed to be in an order that means easy
814 * things are checked first to speed up processing.... however
815 * this means that some packets will manage to get a long way
816 * down this stack and then be rejected, but that's life.
817 */
818 if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
819 (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
820 (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
821 *related = 0;
822 return NF_ACCEPT;
648 } 823 }
649 824
650 if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) 825 /* Now find the contained IP header */
651 offset += 2 * sizeof(__u16); 826 offset += sizeof(_icmph);
652 if (!skb_make_writable(skb, offset)) 827 cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
653 goto out; 828 if (cih == NULL)
829 return NF_ACCEPT; /* The packet looks wrong, ignore */
654 830
655 ip_vs_nat_icmp(skb, pp, cp, 1); 831 pp = ip_vs_proto_get(cih->nexthdr);
832 if (!pp)
833 return NF_ACCEPT;
656 834
657 /* do the statistics and put it back */ 835 /* Is the embedded protocol header present? */
658 ip_vs_out_stats(cp, skb); 836 /* TODO: we don't support fragmentation at the moment anyways */
837 if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
838 return NF_ACCEPT;
659 839
660 skb->ipvs_property = 1; 840 IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMPv6 for");
661 verdict = NF_ACCEPT;
662 841
663 out: 842 offset += sizeof(struct ipv6hdr);
664 __ip_vs_conn_put(cp);
665 843
666 return verdict; 844 ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
845 /* The embedded headers contain source and dest in reverse order */
846 cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
847 if (!cp)
848 return NF_ACCEPT;
849
850 ipv6_addr_copy(&snet.in6, &iph->saddr);
851 return handle_response_icmp(AF_INET6, skb, &snet, cih->nexthdr, cp,
852 pp, offset, sizeof(struct ipv6hdr));
667} 853}
854#endif
668 855
669static inline int is_tcp_reset(const struct sk_buff *skb) 856static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
670{ 857{
671 struct tcphdr _tcph, *th; 858 struct tcphdr _tcph, *th;
672 859
673 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 860 th = skb_header_pointer(skb, nh_len, sizeof(_tcph), &_tcph);
674 if (th == NULL) 861 if (th == NULL)
675 return 0; 862 return 0;
676 return th->rst; 863 return th->rst;
677} 864}
678 865
866/* Handle response packets: rewrite addresses and send away...
867 * Used for NAT and local client.
868 */
869static unsigned int
870handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
871 struct ip_vs_conn *cp, int ihl)
872{
873 IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
874
875 if (!skb_make_writable(skb, ihl))
876 goto drop;
877
878 /* mangle the packet */
879 if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
880 goto drop;
881
882#ifdef CONFIG_IP_VS_IPV6
883 if (af == AF_INET6)
884 ipv6_hdr(skb)->saddr = cp->vaddr.in6;
885 else
886#endif
887 {
888 ip_hdr(skb)->saddr = cp->vaddr.ip;
889 ip_send_check(ip_hdr(skb));
890 }
891
892 /* For policy routing, packets originating from this
893 * machine itself may be routed differently to packets
894 * passing through. We want this packet to be routed as
895 * if it came from this machine itself. So re-compute
896 * the routing information.
897 */
898#ifdef CONFIG_IP_VS_IPV6
899 if (af == AF_INET6) {
900 if (ip6_route_me_harder(skb) != 0)
901 goto drop;
902 } else
903#endif
904 if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
905 goto drop;
906
907 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
908
909 ip_vs_out_stats(cp, skb);
910 ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
911 ip_vs_conn_put(cp);
912
913 skb->ipvs_property = 1;
914
915 LeaveFunction(11);
916 return NF_ACCEPT;
917
918drop:
919 ip_vs_conn_put(cp);
920 kfree_skb(skb);
921 return NF_STOLEN;
922}
923
679/* 924/*
680 * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT. 925 * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT.
681 * Check if outgoing packet belongs to the established ip_vs_conn, 926 * Check if outgoing packet belongs to the established ip_vs_conn.
682 * rewrite addresses of the packet and send it on its way...
683 */ 927 */
684static unsigned int 928static unsigned int
685ip_vs_out(unsigned int hooknum, struct sk_buff *skb, 929ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
686 const struct net_device *in, const struct net_device *out, 930 const struct net_device *in, const struct net_device *out,
687 int (*okfn)(struct sk_buff *)) 931 int (*okfn)(struct sk_buff *))
688{ 932{
689 struct iphdr *iph; 933 struct ip_vs_iphdr iph;
690 struct ip_vs_protocol *pp; 934 struct ip_vs_protocol *pp;
691 struct ip_vs_conn *cp; 935 struct ip_vs_conn *cp;
692 int ihl; 936 int af;
693 937
694 EnterFunction(11); 938 EnterFunction(11);
695 939
940 af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
941
696 if (skb->ipvs_property) 942 if (skb->ipvs_property)
697 return NF_ACCEPT; 943 return NF_ACCEPT;
698 944
699 iph = ip_hdr(skb); 945 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
700 if (unlikely(iph->protocol == IPPROTO_ICMP)) { 946#ifdef CONFIG_IP_VS_IPV6
701 int related, verdict = ip_vs_out_icmp(skb, &related); 947 if (af == AF_INET6) {
948 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
949 int related, verdict = ip_vs_out_icmp_v6(skb, &related);
702 950
703 if (related) 951 if (related)
704 return verdict; 952 return verdict;
705 iph = ip_hdr(skb); 953 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
706 } 954 }
955 } else
956#endif
957 if (unlikely(iph.protocol == IPPROTO_ICMP)) {
958 int related, verdict = ip_vs_out_icmp(skb, &related);
707 959
708 pp = ip_vs_proto_get(iph->protocol); 960 if (related)
961 return verdict;
962 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
963 }
964
965 pp = ip_vs_proto_get(iph.protocol);
709 if (unlikely(!pp)) 966 if (unlikely(!pp))
710 return NF_ACCEPT; 967 return NF_ACCEPT;
711 968
712 /* reassemble IP fragments */ 969 /* reassemble IP fragments */
713 if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) && 970#ifdef CONFIG_IP_VS_IPV6
714 !pp->dont_defrag)) { 971 if (af == AF_INET6) {
715 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) 972 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
716 return NF_STOLEN; 973 int related, verdict = ip_vs_out_icmp_v6(skb, &related);
717 iph = ip_hdr(skb); 974
718 } 975 if (related)
976 return verdict;
719 977
720 ihl = iph->ihl << 2; 978 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
979 }
980 } else
981#endif
982 if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
983 !pp->dont_defrag)) {
984 if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
985 return NF_STOLEN;
986
987 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
988 }
721 989
722 /* 990 /*
723 * Check if the packet belongs to an existing entry 991 * Check if the packet belongs to an existing entry
724 */ 992 */
725 cp = pp->conn_out_get(skb, pp, iph, ihl, 0); 993 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
726 994
727 if (unlikely(!cp)) { 995 if (unlikely(!cp)) {
728 if (sysctl_ip_vs_nat_icmp_send && 996 if (sysctl_ip_vs_nat_icmp_send &&
@@ -730,21 +998,31 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
730 pp->protocol == IPPROTO_UDP)) { 998 pp->protocol == IPPROTO_UDP)) {
731 __be16 _ports[2], *pptr; 999 __be16 _ports[2], *pptr;
732 1000
733 pptr = skb_header_pointer(skb, ihl, 1001 pptr = skb_header_pointer(skb, iph.len,
734 sizeof(_ports), _ports); 1002 sizeof(_ports), _ports);
735 if (pptr == NULL) 1003 if (pptr == NULL)
736 return NF_ACCEPT; /* Not for me */ 1004 return NF_ACCEPT; /* Not for me */
737 if (ip_vs_lookup_real_service(iph->protocol, 1005 if (ip_vs_lookup_real_service(af, iph.protocol,
738 iph->saddr, pptr[0])) { 1006 &iph.saddr,
1007 pptr[0])) {
739 /* 1008 /*
740 * Notify the real server: there is no 1009 * Notify the real server: there is no
741 * existing entry if it is not RST 1010 * existing entry if it is not RST
742 * packet or not TCP packet. 1011 * packet or not TCP packet.
743 */ 1012 */
744 if (iph->protocol != IPPROTO_TCP 1013 if (iph.protocol != IPPROTO_TCP
745 || !is_tcp_reset(skb)) { 1014 || !is_tcp_reset(skb, iph.len)) {
746 icmp_send(skb,ICMP_DEST_UNREACH, 1015#ifdef CONFIG_IP_VS_IPV6
747 ICMP_PORT_UNREACH, 0); 1016 if (af == AF_INET6)
1017 icmpv6_send(skb,
1018 ICMPV6_DEST_UNREACH,
1019 ICMPV6_PORT_UNREACH,
1020 0, skb->dev);
1021 else
1022#endif
1023 icmp_send(skb,
1024 ICMP_DEST_UNREACH,
1025 ICMP_PORT_UNREACH, 0);
748 return NF_DROP; 1026 return NF_DROP;
749 } 1027 }
750 } 1028 }
@@ -754,41 +1032,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
754 return NF_ACCEPT; 1032 return NF_ACCEPT;
755 } 1033 }
756 1034
757 IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); 1035 return handle_response(af, skb, pp, cp, iph.len);
758
759 if (!skb_make_writable(skb, ihl))
760 goto drop;
761
762 /* mangle the packet */
763 if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
764 goto drop;
765 ip_hdr(skb)->saddr = cp->vaddr;
766 ip_send_check(ip_hdr(skb));
767
768 /* For policy routing, packets originating from this
769 * machine itself may be routed differently to packets
770 * passing through. We want this packet to be routed as
771 * if it came from this machine itself. So re-compute
772 * the routing information.
773 */
774 if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
775 goto drop;
776
777 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
778
779 ip_vs_out_stats(cp, skb);
780 ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
781 ip_vs_conn_put(cp);
782
783 skb->ipvs_property = 1;
784
785 LeaveFunction(11);
786 return NF_ACCEPT;
787
788 drop:
789 ip_vs_conn_put(cp);
790 kfree_skb(skb);
791 return NF_STOLEN;
792} 1036}
793 1037
794 1038
@@ -804,9 +1048,11 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
804 struct iphdr *iph; 1048 struct iphdr *iph;
805 struct icmphdr _icmph, *ic; 1049 struct icmphdr _icmph, *ic;
806 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ 1050 struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
1051 struct ip_vs_iphdr ciph;
807 struct ip_vs_conn *cp; 1052 struct ip_vs_conn *cp;
808 struct ip_vs_protocol *pp; 1053 struct ip_vs_protocol *pp;
809 unsigned int offset, ihl, verdict; 1054 unsigned int offset, ihl, verdict;
1055 union nf_inet_addr snet;
810 1056
811 *related = 1; 1057 *related = 1;
812 1058
@@ -860,10 +1106,20 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
860 1106
861 offset += cih->ihl * 4; 1107 offset += cih->ihl * 4;
862 1108
1109 ip_vs_fill_iphdr(AF_INET, cih, &ciph);
863 /* The embedded headers contain source and dest in reverse order */ 1110 /* The embedded headers contain source and dest in reverse order */
864 cp = pp->conn_in_get(skb, pp, cih, offset, 1); 1111 cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
865 if (!cp) 1112 if (!cp) {
1113 /* The packet could also belong to a local client */
1114 cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
1115 if (cp) {
1116 snet.ip = iph->saddr;
1117 return handle_response_icmp(AF_INET, skb, &snet,
1118 cih->protocol, cp, pp,
1119 offset, ihl);
1120 }
866 return NF_ACCEPT; 1121 return NF_ACCEPT;
1122 }
867 1123
868 verdict = NF_DROP; 1124 verdict = NF_DROP;
869 1125
@@ -888,6 +1144,105 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
888 return verdict; 1144 return verdict;
889} 1145}
890 1146
1147#ifdef CONFIG_IP_VS_IPV6
1148static int
1149ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1150{
1151 struct ipv6hdr *iph;
1152 struct icmp6hdr _icmph, *ic;
1153 struct ipv6hdr _ciph, *cih; /* The ip header contained
1154 within the ICMP */
1155 struct ip_vs_iphdr ciph;
1156 struct ip_vs_conn *cp;
1157 struct ip_vs_protocol *pp;
1158 unsigned int offset, verdict;
1159 union nf_inet_addr snet;
1160
1161 *related = 1;
1162
1163 /* reassemble IP fragments */
1164 if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
1165 if (ip_vs_gather_frags_v6(skb, hooknum == NF_INET_LOCAL_IN ?
1166 IP_DEFRAG_VS_IN :
1167 IP_DEFRAG_VS_FWD))
1168 return NF_STOLEN;
1169 }
1170
1171 iph = ipv6_hdr(skb);
1172 offset = sizeof(struct ipv6hdr);
1173 ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
1174 if (ic == NULL)
1175 return NF_DROP;
1176
1177 IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
1178 ic->icmp6_type, ntohs(icmpv6_id(ic)),
1179 NIP6(iph->saddr), NIP6(iph->daddr));
1180
1181 /*
1182 * Work through seeing if this is for us.
1183 * These checks are supposed to be in an order that means easy
1184 * things are checked first to speed up processing.... however
1185 * this means that some packets will manage to get a long way
1186 * down this stack and then be rejected, but that's life.
1187 */
1188 if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
1189 (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
1190 (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
1191 *related = 0;
1192 return NF_ACCEPT;
1193 }
1194
1195 /* Now find the contained IP header */
1196 offset += sizeof(_icmph);
1197 cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
1198 if (cih == NULL)
1199 return NF_ACCEPT; /* The packet looks wrong, ignore */
1200
1201 pp = ip_vs_proto_get(cih->nexthdr);
1202 if (!pp)
1203 return NF_ACCEPT;
1204
1205 /* Is the embedded protocol header present? */
1206 /* TODO: we don't support fragmentation at the moment anyways */
1207 if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
1208 return NF_ACCEPT;
1209
1210 IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMPv6 for");
1211
1212 offset += sizeof(struct ipv6hdr);
1213
1214 ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
1215 /* The embedded headers contain source and dest in reverse order */
1216 cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1);
1217 if (!cp) {
1218 /* The packet could also belong to a local client */
1219 cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
1220 if (cp) {
1221 ipv6_addr_copy(&snet.in6, &iph->saddr);
1222 return handle_response_icmp(AF_INET6, skb, &snet,
1223 cih->nexthdr,
1224 cp, pp, offset,
1225 sizeof(struct ipv6hdr));
1226 }
1227 return NF_ACCEPT;
1228 }
1229
1230 verdict = NF_DROP;
1231
1232 /* do the statistics and put it back */
1233 ip_vs_in_stats(cp, skb);
1234 if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
1235 offset += 2 * sizeof(__u16);
1236 verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
1237 /* do not touch skb anymore */
1238
1239 __ip_vs_conn_put(cp);
1240
1241 return verdict;
1242}
1243#endif
1244
1245
891/* 1246/*
892 * Check if it's for virtual services, look it up, 1247 * Check if it's for virtual services, look it up,
893 * and send it on its way... 1248 * and send it on its way...
@@ -897,50 +1252,54 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
897 const struct net_device *in, const struct net_device *out, 1252 const struct net_device *in, const struct net_device *out,
898 int (*okfn)(struct sk_buff *)) 1253 int (*okfn)(struct sk_buff *))
899{ 1254{
900 struct iphdr *iph; 1255 struct ip_vs_iphdr iph;
901 struct ip_vs_protocol *pp; 1256 struct ip_vs_protocol *pp;
902 struct ip_vs_conn *cp; 1257 struct ip_vs_conn *cp;
903 int ret, restart; 1258 int ret, restart, af;
904 int ihl; 1259
1260 af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
1261
1262 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
905 1263
906 /* 1264 /*
907 * Big tappo: only PACKET_HOST (neither loopback nor mcasts) 1265 * Big tappo: only PACKET_HOST, including loopback for local client
908 * ... don't know why 1st test DOES NOT include 2nd (?) 1266 * Don't handle local packets on IPv6 for now
909 */ 1267 */
910 if (unlikely(skb->pkt_type != PACKET_HOST 1268 if (unlikely(skb->pkt_type != PACKET_HOST)) {
911 || skb->dev->flags & IFF_LOOPBACK || skb->sk)) { 1269 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
912 IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", 1270 skb->pkt_type,
913 skb->pkt_type, 1271 iph.protocol,
914 ip_hdr(skb)->protocol, 1272 IP_VS_DBG_ADDR(af, &iph.daddr));
915 NIPQUAD(ip_hdr(skb)->daddr));
916 return NF_ACCEPT; 1273 return NF_ACCEPT;
917 } 1274 }
918 1275
919 iph = ip_hdr(skb); 1276 if (unlikely(iph.protocol == IPPROTO_ICMP)) {
920 if (unlikely(iph->protocol == IPPROTO_ICMP)) {
921 int related, verdict = ip_vs_in_icmp(skb, &related, hooknum); 1277 int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
922 1278
923 if (related) 1279 if (related)
924 return verdict; 1280 return verdict;
925 iph = ip_hdr(skb); 1281 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
926 } 1282 }
927 1283
928 /* Protocol supported? */ 1284 /* Protocol supported? */
929 pp = ip_vs_proto_get(iph->protocol); 1285 pp = ip_vs_proto_get(iph.protocol);
930 if (unlikely(!pp)) 1286 if (unlikely(!pp))
931 return NF_ACCEPT; 1287 return NF_ACCEPT;
932 1288
933 ihl = iph->ihl << 2;
934
935 /* 1289 /*
936 * Check if the packet belongs to an existing connection entry 1290 * Check if the packet belongs to an existing connection entry
937 */ 1291 */
938 cp = pp->conn_in_get(skb, pp, iph, ihl, 0); 1292 cp = pp->conn_in_get(af, skb, pp, &iph, iph.len, 0);
939 1293
940 if (unlikely(!cp)) { 1294 if (unlikely(!cp)) {
941 int v; 1295 int v;
942 1296
943 if (!pp->conn_schedule(skb, pp, &v, &cp)) 1297 /* For local client packets, it could be a response */
1298 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
1299 if (cp)
1300 return handle_response(af, skb, pp, cp, iph.len);
1301
1302 if (!pp->conn_schedule(af, skb, pp, &v, &cp))
944 return v; 1303 return v;
945 } 1304 }
946 1305
@@ -984,7 +1343,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
984 * encorage the standby servers to update the connections timeout 1343 * encorage the standby servers to update the connections timeout
985 */ 1344 */
986 atomic_inc(&cp->in_pkts); 1345 atomic_inc(&cp->in_pkts);
987 if ((ip_vs_sync_state & IP_VS_STATE_MASTER) && 1346 if (af == AF_INET &&
1347 (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
988 (((cp->protocol != IPPROTO_TCP || 1348 (((cp->protocol != IPPROTO_TCP ||
989 cp->state == IP_VS_TCP_S_ESTABLISHED) && 1349 cp->state == IP_VS_TCP_S_ESTABLISHED) &&
990 (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1] 1350 (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
@@ -1023,6 +1383,21 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
1023 return ip_vs_in_icmp(skb, &r, hooknum); 1383 return ip_vs_in_icmp(skb, &r, hooknum);
1024} 1384}
1025 1385
1386#ifdef CONFIG_IP_VS_IPV6
1387static unsigned int
1388ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1389 const struct net_device *in, const struct net_device *out,
1390 int (*okfn)(struct sk_buff *))
1391{
1392 int r;
1393
1394 if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
1395 return NF_ACCEPT;
1396
1397 return ip_vs_in_icmp_v6(skb, &r, hooknum);
1398}
1399#endif
1400
1026 1401
1027static struct nf_hook_ops ip_vs_ops[] __read_mostly = { 1402static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1028 /* After packet filtering, forward packet through VS/DR, VS/TUN, 1403 /* After packet filtering, forward packet through VS/DR, VS/TUN,
@@ -1060,6 +1435,43 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1060 .hooknum = NF_INET_POST_ROUTING, 1435 .hooknum = NF_INET_POST_ROUTING,
1061 .priority = NF_IP_PRI_NAT_SRC-1, 1436 .priority = NF_IP_PRI_NAT_SRC-1,
1062 }, 1437 },
1438#ifdef CONFIG_IP_VS_IPV6
1439 /* After packet filtering, forward packet through VS/DR, VS/TUN,
1440 * or VS/NAT(change destination), so that filtering rules can be
1441 * applied to IPVS. */
1442 {
1443 .hook = ip_vs_in,
1444 .owner = THIS_MODULE,
1445 .pf = PF_INET6,
1446 .hooknum = NF_INET_LOCAL_IN,
1447 .priority = 100,
1448 },
1449 /* After packet filtering, change source only for VS/NAT */
1450 {
1451 .hook = ip_vs_out,
1452 .owner = THIS_MODULE,
1453 .pf = PF_INET6,
1454 .hooknum = NF_INET_FORWARD,
1455 .priority = 100,
1456 },
1457 /* After packet filtering (but before ip_vs_out_icmp), catch icmp
1458 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
1459 {
1460 .hook = ip_vs_forward_icmp_v6,
1461 .owner = THIS_MODULE,
1462 .pf = PF_INET6,
1463 .hooknum = NF_INET_FORWARD,
1464 .priority = 99,
1465 },
1466 /* Before the netfilter connection tracking, exit from POST_ROUTING */
1467 {
1468 .hook = ip_vs_post_routing,
1469 .owner = THIS_MODULE,
1470 .pf = PF_INET6,
1471 .hooknum = NF_INET_POST_ROUTING,
1472 .priority = NF_IP6_PRI_NAT_SRC-1,
1473 },
1474#endif
1063}; 1475};
1064 1476
1065 1477
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index ede101eeec17..993a83fb0d56 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -35,6 +35,10 @@
35 35
36#include <net/net_namespace.h> 36#include <net/net_namespace.h>
37#include <net/ip.h> 37#include <net/ip.h>
38#ifdef CONFIG_IP_VS_IPV6
39#include <net/ipv6.h>
40#include <net/ip6_route.h>
41#endif
38#include <net/route.h> 42#include <net/route.h>
39#include <net/sock.h> 43#include <net/sock.h>
40#include <net/genetlink.h> 44#include <net/genetlink.h>
@@ -91,6 +95,26 @@ int ip_vs_get_debug_level(void)
91} 95}
92#endif 96#endif
93 97
98#ifdef CONFIG_IP_VS_IPV6
99/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
100static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr)
101{
102 struct rt6_info *rt;
103 struct flowi fl = {
104 .oif = 0,
105 .nl_u = {
106 .ip6_u = {
107 .daddr = *addr,
108 .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
109 };
110
111 rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
112 if (rt && rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK))
113 return 1;
114
115 return 0;
116}
117#endif
94/* 118/*
95 * update_defense_level is called from keventd and from sysctl, 119 * update_defense_level is called from keventd and from sysctl,
96 * so it needs to protect itself from softirqs 120 * so it needs to protect itself from softirqs
@@ -282,11 +306,19 @@ static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
282 * Returns hash value for virtual service 306 * Returns hash value for virtual service
283 */ 307 */
284static __inline__ unsigned 308static __inline__ unsigned
285ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port) 309ip_vs_svc_hashkey(int af, unsigned proto, const union nf_inet_addr *addr,
310 __be16 port)
286{ 311{
287 register unsigned porth = ntohs(port); 312 register unsigned porth = ntohs(port);
313 __be32 addr_fold = addr->ip;
314
315#ifdef CONFIG_IP_VS_IPV6
316 if (af == AF_INET6)
317 addr_fold = addr->ip6[0]^addr->ip6[1]^
318 addr->ip6[2]^addr->ip6[3];
319#endif
288 320
289 return (proto^ntohl(addr)^(porth>>IP_VS_SVC_TAB_BITS)^porth) 321 return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
290 & IP_VS_SVC_TAB_MASK; 322 & IP_VS_SVC_TAB_MASK;
291} 323}
292 324
@@ -317,7 +349,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
317 /* 349 /*
318 * Hash it by <protocol,addr,port> in ip_vs_svc_table 350 * Hash it by <protocol,addr,port> in ip_vs_svc_table
319 */ 351 */
320 hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port); 352 hash = ip_vs_svc_hashkey(svc->af, svc->protocol, &svc->addr,
353 svc->port);
321 list_add(&svc->s_list, &ip_vs_svc_table[hash]); 354 list_add(&svc->s_list, &ip_vs_svc_table[hash]);
322 } else { 355 } else {
323 /* 356 /*
@@ -363,17 +396,19 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
363/* 396/*
364 * Get service by {proto,addr,port} in the service table. 397 * Get service by {proto,addr,port} in the service table.
365 */ 398 */
366static __inline__ struct ip_vs_service * 399static inline struct ip_vs_service *
367__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport) 400__ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
401 __be16 vport)
368{ 402{
369 unsigned hash; 403 unsigned hash;
370 struct ip_vs_service *svc; 404 struct ip_vs_service *svc;
371 405
372 /* Check for "full" addressed entries */ 406 /* Check for "full" addressed entries */
373 hash = ip_vs_svc_hashkey(protocol, vaddr, vport); 407 hash = ip_vs_svc_hashkey(af, protocol, vaddr, vport);
374 408
375 list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){ 409 list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
376 if ((svc->addr == vaddr) 410 if ((svc->af == af)
411 && ip_vs_addr_equal(af, &svc->addr, vaddr)
377 && (svc->port == vport) 412 && (svc->port == vport)
378 && (svc->protocol == protocol)) { 413 && (svc->protocol == protocol)) {
379 /* HIT */ 414 /* HIT */
@@ -389,7 +424,8 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
389/* 424/*
390 * Get service by {fwmark} in the service table. 425 * Get service by {fwmark} in the service table.
391 */ 426 */
392static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark) 427static inline struct ip_vs_service *
428__ip_vs_svc_fwm_get(int af, __u32 fwmark)
393{ 429{
394 unsigned hash; 430 unsigned hash;
395 struct ip_vs_service *svc; 431 struct ip_vs_service *svc;
@@ -398,7 +434,7 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
398 hash = ip_vs_svc_fwm_hashkey(fwmark); 434 hash = ip_vs_svc_fwm_hashkey(fwmark);
399 435
400 list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) { 436 list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
401 if (svc->fwmark == fwmark) { 437 if (svc->fwmark == fwmark && svc->af == af) {
402 /* HIT */ 438 /* HIT */
403 atomic_inc(&svc->usecnt); 439 atomic_inc(&svc->usecnt);
404 return svc; 440 return svc;
@@ -409,7 +445,8 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
409} 445}
410 446
411struct ip_vs_service * 447struct ip_vs_service *
412ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport) 448ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
449 const union nf_inet_addr *vaddr, __be16 vport)
413{ 450{
414 struct ip_vs_service *svc; 451 struct ip_vs_service *svc;
415 452
@@ -418,14 +455,14 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
418 /* 455 /*
419 * Check the table hashed by fwmark first 456 * Check the table hashed by fwmark first
420 */ 457 */
421 if (fwmark && (svc = __ip_vs_svc_fwm_get(fwmark))) 458 if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark)))
422 goto out; 459 goto out;
423 460
424 /* 461 /*
425 * Check the table hashed by <protocol,addr,port> 462 * Check the table hashed by <protocol,addr,port>
426 * for "full" addressed entries 463 * for "full" addressed entries
427 */ 464 */
428 svc = __ip_vs_service_get(protocol, vaddr, vport); 465 svc = __ip_vs_service_get(af, protocol, vaddr, vport);
429 466
430 if (svc == NULL 467 if (svc == NULL
431 && protocol == IPPROTO_TCP 468 && protocol == IPPROTO_TCP
@@ -435,7 +472,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
435 * Check if ftp service entry exists, the packet 472 * Check if ftp service entry exists, the packet
436 * might belong to FTP data connections. 473 * might belong to FTP data connections.
437 */ 474 */
438 svc = __ip_vs_service_get(protocol, vaddr, FTPPORT); 475 svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT);
439 } 476 }
440 477
441 if (svc == NULL 478 if (svc == NULL
@@ -443,16 +480,16 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
443 /* 480 /*
444 * Check if the catch-all port (port zero) exists 481 * Check if the catch-all port (port zero) exists
445 */ 482 */
446 svc = __ip_vs_service_get(protocol, vaddr, 0); 483 svc = __ip_vs_service_get(af, protocol, vaddr, 0);
447 } 484 }
448 485
449 out: 486 out:
450 read_unlock(&__ip_vs_svc_lock); 487 read_unlock(&__ip_vs_svc_lock);
451 488
452 IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n", 489 IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
453 fwmark, ip_vs_proto_name(protocol), 490 fwmark, ip_vs_proto_name(protocol),
454 NIPQUAD(vaddr), ntohs(vport), 491 IP_VS_DBG_ADDR(af, vaddr), ntohs(vport),
455 svc?"hit":"not hit"); 492 svc ? "hit" : "not hit");
456 493
457 return svc; 494 return svc;
458} 495}
@@ -479,11 +516,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
479/* 516/*
480 * Returns hash value for real service 517 * Returns hash value for real service
481 */ 518 */
482static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port) 519static inline unsigned ip_vs_rs_hashkey(int af,
520 const union nf_inet_addr *addr,
521 __be16 port)
483{ 522{
484 register unsigned porth = ntohs(port); 523 register unsigned porth = ntohs(port);
524 __be32 addr_fold = addr->ip;
525
526#ifdef CONFIG_IP_VS_IPV6
527 if (af == AF_INET6)
528 addr_fold = addr->ip6[0]^addr->ip6[1]^
529 addr->ip6[2]^addr->ip6[3];
530#endif
485 531
486 return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth) 532 return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
487 & IP_VS_RTAB_MASK; 533 & IP_VS_RTAB_MASK;
488} 534}
489 535
@@ -503,7 +549,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
503 * Hash by proto,addr,port, 549 * Hash by proto,addr,port,
504 * which are the parameters of the real service. 550 * which are the parameters of the real service.
505 */ 551 */
506 hash = ip_vs_rs_hashkey(dest->addr, dest->port); 552 hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
553
507 list_add(&dest->d_list, &ip_vs_rtable[hash]); 554 list_add(&dest->d_list, &ip_vs_rtable[hash]);
508 555
509 return 1; 556 return 1;
@@ -530,7 +577,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
530 * Lookup real service by <proto,addr,port> in the real service table. 577 * Lookup real service by <proto,addr,port> in the real service table.
531 */ 578 */
532struct ip_vs_dest * 579struct ip_vs_dest *
533ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport) 580ip_vs_lookup_real_service(int af, __u16 protocol,
581 const union nf_inet_addr *daddr,
582 __be16 dport)
534{ 583{
535 unsigned hash; 584 unsigned hash;
536 struct ip_vs_dest *dest; 585 struct ip_vs_dest *dest;
@@ -539,11 +588,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
539 * Check for "full" addressed entries 588 * Check for "full" addressed entries
540 * Return the first found entry 589 * Return the first found entry
541 */ 590 */
542 hash = ip_vs_rs_hashkey(daddr, dport); 591 hash = ip_vs_rs_hashkey(af, daddr, dport);
543 592
544 read_lock(&__ip_vs_rs_lock); 593 read_lock(&__ip_vs_rs_lock);
545 list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) { 594 list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
546 if ((dest->addr == daddr) 595 if ((dest->af == af)
596 && ip_vs_addr_equal(af, &dest->addr, daddr)
547 && (dest->port == dport) 597 && (dest->port == dport)
548 && ((dest->protocol == protocol) || 598 && ((dest->protocol == protocol) ||
549 dest->vfwmark)) { 599 dest->vfwmark)) {
@@ -561,7 +611,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
561 * Lookup destination by {addr,port} in the given service 611 * Lookup destination by {addr,port} in the given service
562 */ 612 */
563static struct ip_vs_dest * 613static struct ip_vs_dest *
564ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) 614ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
615 __be16 dport)
565{ 616{
566 struct ip_vs_dest *dest; 617 struct ip_vs_dest *dest;
567 618
@@ -569,7 +620,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
569 * Find the destination for the given service 620 * Find the destination for the given service
570 */ 621 */
571 list_for_each_entry(dest, &svc->destinations, n_list) { 622 list_for_each_entry(dest, &svc->destinations, n_list) {
572 if ((dest->addr == daddr) && (dest->port == dport)) { 623 if ((dest->af == svc->af)
624 && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
625 && (dest->port == dport)) {
573 /* HIT */ 626 /* HIT */
574 return dest; 627 return dest;
575 } 628 }
@@ -588,13 +641,15 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
588 * ip_vs_lookup_real_service() looked promissing, but 641 * ip_vs_lookup_real_service() looked promissing, but
589 * seems not working as expected. 642 * seems not working as expected.
590 */ 643 */
591struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport, 644struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
592 __be32 vaddr, __be16 vport, __u16 protocol) 645 __be16 dport,
646 const union nf_inet_addr *vaddr,
647 __be16 vport, __u16 protocol)
593{ 648{
594 struct ip_vs_dest *dest; 649 struct ip_vs_dest *dest;
595 struct ip_vs_service *svc; 650 struct ip_vs_service *svc;
596 651
597 svc = ip_vs_service_get(0, protocol, vaddr, vport); 652 svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
598 if (!svc) 653 if (!svc)
599 return NULL; 654 return NULL;
600 dest = ip_vs_lookup_dest(svc, daddr, dport); 655 dest = ip_vs_lookup_dest(svc, daddr, dport);
@@ -615,7 +670,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
615 * scheduling. 670 * scheduling.
616 */ 671 */
617static struct ip_vs_dest * 672static struct ip_vs_dest *
618ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) 673ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
674 __be16 dport)
619{ 675{
620 struct ip_vs_dest *dest, *nxt; 676 struct ip_vs_dest *dest, *nxt;
621 677
@@ -623,17 +679,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
623 * Find the destination in trash 679 * Find the destination in trash
624 */ 680 */
625 list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) { 681 list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
626 IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, " 682 IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
627 "dest->refcnt=%d\n", 683 "dest->refcnt=%d\n",
628 dest->vfwmark, 684 dest->vfwmark,
629 NIPQUAD(dest->addr), ntohs(dest->port), 685 IP_VS_DBG_ADDR(svc->af, &dest->addr),
630 atomic_read(&dest->refcnt)); 686 ntohs(dest->port),
631 if (dest->addr == daddr && 687 atomic_read(&dest->refcnt));
688 if (dest->af == svc->af &&
689 ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
632 dest->port == dport && 690 dest->port == dport &&
633 dest->vfwmark == svc->fwmark && 691 dest->vfwmark == svc->fwmark &&
634 dest->protocol == svc->protocol && 692 dest->protocol == svc->protocol &&
635 (svc->fwmark || 693 (svc->fwmark ||
636 (dest->vaddr == svc->addr && 694 (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
637 dest->vport == svc->port))) { 695 dest->vport == svc->port))) {
638 /* HIT */ 696 /* HIT */
639 return dest; 697 return dest;
@@ -643,10 +701,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
643 * Try to purge the destination from trash if not referenced 701 * Try to purge the destination from trash if not referenced
644 */ 702 */
645 if (atomic_read(&dest->refcnt) == 1) { 703 if (atomic_read(&dest->refcnt) == 1) {
646 IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u " 704 IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
647 "from trash\n", 705 "from trash\n",
648 dest->vfwmark, 706 dest->vfwmark,
649 NIPQUAD(dest->addr), ntohs(dest->port)); 707 IP_VS_DBG_ADDR(svc->af, &dest->addr),
708 ntohs(dest->port));
650 list_del(&dest->n_list); 709 list_del(&dest->n_list);
651 ip_vs_dst_reset(dest); 710 ip_vs_dst_reset(dest);
652 __ip_vs_unbind_svc(dest); 711 __ip_vs_unbind_svc(dest);
@@ -685,18 +744,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
685{ 744{
686 spin_lock_bh(&stats->lock); 745 spin_lock_bh(&stats->lock);
687 746
688 stats->conns = 0; 747 memset(&stats->ustats, 0, sizeof(stats->ustats));
689 stats->inpkts = 0;
690 stats->outpkts = 0;
691 stats->inbytes = 0;
692 stats->outbytes = 0;
693
694 stats->cps = 0;
695 stats->inpps = 0;
696 stats->outpps = 0;
697 stats->inbps = 0;
698 stats->outbps = 0;
699
700 ip_vs_zero_estimator(stats); 748 ip_vs_zero_estimator(stats);
701 749
702 spin_unlock_bh(&stats->lock); 750 spin_unlock_bh(&stats->lock);
@@ -707,7 +755,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
707 */ 755 */
708static void 756static void
709__ip_vs_update_dest(struct ip_vs_service *svc, 757__ip_vs_update_dest(struct ip_vs_service *svc,
710 struct ip_vs_dest *dest, struct ip_vs_dest_user *udest) 758 struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
711{ 759{
712 int conn_flags; 760 int conn_flags;
713 761
@@ -716,10 +764,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
716 conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE; 764 conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
717 765
718 /* check if local node and update the flags */ 766 /* check if local node and update the flags */
719 if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) { 767#ifdef CONFIG_IP_VS_IPV6
720 conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) 768 if (svc->af == AF_INET6) {
721 | IP_VS_CONN_F_LOCALNODE; 769 if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
722 } 770 conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
771 | IP_VS_CONN_F_LOCALNODE;
772 }
773 } else
774#endif
775 if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
776 conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
777 | IP_VS_CONN_F_LOCALNODE;
778 }
723 779
724 /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */ 780 /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
725 if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) { 781 if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
@@ -760,7 +816,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
760 * Create a destination for the given service 816 * Create a destination for the given service
761 */ 817 */
762static int 818static int
763ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest, 819ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
764 struct ip_vs_dest **dest_p) 820 struct ip_vs_dest **dest_p)
765{ 821{
766 struct ip_vs_dest *dest; 822 struct ip_vs_dest *dest;
@@ -768,9 +824,20 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
768 824
769 EnterFunction(2); 825 EnterFunction(2);
770 826
771 atype = inet_addr_type(&init_net, udest->addr); 827#ifdef CONFIG_IP_VS_IPV6
772 if (atype != RTN_LOCAL && atype != RTN_UNICAST) 828 if (svc->af == AF_INET6) {
773 return -EINVAL; 829 atype = ipv6_addr_type(&udest->addr.in6);
830 if ((!(atype & IPV6_ADDR_UNICAST) ||
831 atype & IPV6_ADDR_LINKLOCAL) &&
832 !__ip_vs_addr_is_local_v6(&udest->addr.in6))
833 return -EINVAL;
834 } else
835#endif
836 {
837 atype = inet_addr_type(&init_net, udest->addr.ip);
838 if (atype != RTN_LOCAL && atype != RTN_UNICAST)
839 return -EINVAL;
840 }
774 841
775 dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); 842 dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
776 if (dest == NULL) { 843 if (dest == NULL) {
@@ -778,11 +845,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
778 return -ENOMEM; 845 return -ENOMEM;
779 } 846 }
780 847
848 dest->af = svc->af;
781 dest->protocol = svc->protocol; 849 dest->protocol = svc->protocol;
782 dest->vaddr = svc->addr; 850 dest->vaddr = svc->addr;
783 dest->vport = svc->port; 851 dest->vport = svc->port;
784 dest->vfwmark = svc->fwmark; 852 dest->vfwmark = svc->fwmark;
785 dest->addr = udest->addr; 853 ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
786 dest->port = udest->port; 854 dest->port = udest->port;
787 855
788 atomic_set(&dest->activeconns, 0); 856 atomic_set(&dest->activeconns, 0);
@@ -807,10 +875,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
807 * Add a destination into an existing service 875 * Add a destination into an existing service
808 */ 876 */
809static int 877static int
810ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) 878ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
811{ 879{
812 struct ip_vs_dest *dest; 880 struct ip_vs_dest *dest;
813 __be32 daddr = udest->addr; 881 union nf_inet_addr daddr;
814 __be16 dport = udest->port; 882 __be16 dport = udest->port;
815 int ret; 883 int ret;
816 884
@@ -827,10 +895,13 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
827 return -ERANGE; 895 return -ERANGE;
828 } 896 }
829 897
898 ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
899
830 /* 900 /*
831 * Check if the dest already exists in the list 901 * Check if the dest already exists in the list
832 */ 902 */
833 dest = ip_vs_lookup_dest(svc, daddr, dport); 903 dest = ip_vs_lookup_dest(svc, &daddr, dport);
904
834 if (dest != NULL) { 905 if (dest != NULL) {
835 IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n"); 906 IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
836 return -EEXIST; 907 return -EEXIST;
@@ -840,15 +911,17 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
840 * Check if the dest already exists in the trash and 911 * Check if the dest already exists in the trash and
841 * is from the same service 912 * is from the same service
842 */ 913 */
843 dest = ip_vs_trash_get_dest(svc, daddr, dport); 914 dest = ip_vs_trash_get_dest(svc, &daddr, dport);
915
844 if (dest != NULL) { 916 if (dest != NULL) {
845 IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, " 917 IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
846 "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n", 918 "dest->refcnt=%d, service %u/%s:%u\n",
847 NIPQUAD(daddr), ntohs(dport), 919 IP_VS_DBG_ADDR(svc->af, &daddr), ntohs(dport),
848 atomic_read(&dest->refcnt), 920 atomic_read(&dest->refcnt),
849 dest->vfwmark, 921 dest->vfwmark,
850 NIPQUAD(dest->vaddr), 922 IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
851 ntohs(dest->vport)); 923 ntohs(dest->vport));
924
852 __ip_vs_update_dest(svc, dest, udest); 925 __ip_vs_update_dest(svc, dest, udest);
853 926
854 /* 927 /*
@@ -915,10 +988,10 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
915 * Edit a destination in the given service 988 * Edit a destination in the given service
916 */ 989 */
917static int 990static int
918ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) 991ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
919{ 992{
920 struct ip_vs_dest *dest; 993 struct ip_vs_dest *dest;
921 __be32 daddr = udest->addr; 994 union nf_inet_addr daddr;
922 __be16 dport = udest->port; 995 __be16 dport = udest->port;
923 996
924 EnterFunction(2); 997 EnterFunction(2);
@@ -934,10 +1007,13 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
934 return -ERANGE; 1007 return -ERANGE;
935 } 1008 }
936 1009
1010 ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
1011
937 /* 1012 /*
938 * Lookup the destination list 1013 * Lookup the destination list
939 */ 1014 */
940 dest = ip_vs_lookup_dest(svc, daddr, dport); 1015 dest = ip_vs_lookup_dest(svc, &daddr, dport);
1016
941 if (dest == NULL) { 1017 if (dest == NULL) {
942 IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n"); 1018 IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
943 return -ENOENT; 1019 return -ENOENT;
@@ -991,10 +1067,11 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
991 atomic_dec(&dest->svc->refcnt); 1067 atomic_dec(&dest->svc->refcnt);
992 kfree(dest); 1068 kfree(dest);
993 } else { 1069 } else {
994 IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, " 1070 IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, "
995 "dest->refcnt=%d\n", 1071 "dest->refcnt=%d\n",
996 NIPQUAD(dest->addr), ntohs(dest->port), 1072 IP_VS_DBG_ADDR(dest->af, &dest->addr),
997 atomic_read(&dest->refcnt)); 1073 ntohs(dest->port),
1074 atomic_read(&dest->refcnt));
998 list_add(&dest->n_list, &ip_vs_dest_trash); 1075 list_add(&dest->n_list, &ip_vs_dest_trash);
999 atomic_inc(&dest->refcnt); 1076 atomic_inc(&dest->refcnt);
1000 } 1077 }
@@ -1028,15 +1105,15 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
1028 * Delete a destination server in the given service 1105 * Delete a destination server in the given service
1029 */ 1106 */
1030static int 1107static int
1031ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest) 1108ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
1032{ 1109{
1033 struct ip_vs_dest *dest; 1110 struct ip_vs_dest *dest;
1034 __be32 daddr = udest->addr;
1035 __be16 dport = udest->port; 1111 __be16 dport = udest->port;
1036 1112
1037 EnterFunction(2); 1113 EnterFunction(2);
1038 1114
1039 dest = ip_vs_lookup_dest(svc, daddr, dport); 1115 dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
1116
1040 if (dest == NULL) { 1117 if (dest == NULL) {
1041 IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n"); 1118 IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
1042 return -ENOENT; 1119 return -ENOENT;
@@ -1071,7 +1148,8 @@ ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
1071 * Add a service into the service hash table 1148 * Add a service into the service hash table
1072 */ 1149 */
1073static int 1150static int
1074ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) 1151ip_vs_add_service(struct ip_vs_service_user_kern *u,
1152 struct ip_vs_service **svc_p)
1075{ 1153{
1076 int ret = 0; 1154 int ret = 0;
1077 struct ip_vs_scheduler *sched = NULL; 1155 struct ip_vs_scheduler *sched = NULL;
@@ -1089,6 +1167,19 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
1089 goto out_mod_dec; 1167 goto out_mod_dec;
1090 } 1168 }
1091 1169
1170#ifdef CONFIG_IP_VS_IPV6
1171 if (u->af == AF_INET6) {
1172 if (!sched->supports_ipv6) {
1173 ret = -EAFNOSUPPORT;
1174 goto out_err;
1175 }
1176 if ((u->netmask < 1) || (u->netmask > 128)) {
1177 ret = -EINVAL;
1178 goto out_err;
1179 }
1180 }
1181#endif
1182
1092 svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC); 1183 svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
1093 if (svc == NULL) { 1184 if (svc == NULL) {
1094 IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n"); 1185 IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
@@ -1100,8 +1191,9 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
1100 atomic_set(&svc->usecnt, 1); 1191 atomic_set(&svc->usecnt, 1);
1101 atomic_set(&svc->refcnt, 0); 1192 atomic_set(&svc->refcnt, 0);
1102 1193
1194 svc->af = u->af;
1103 svc->protocol = u->protocol; 1195 svc->protocol = u->protocol;
1104 svc->addr = u->addr; 1196 ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
1105 svc->port = u->port; 1197 svc->port = u->port;
1106 svc->fwmark = u->fwmark; 1198 svc->fwmark = u->fwmark;
1107 svc->flags = u->flags; 1199 svc->flags = u->flags;
@@ -1125,7 +1217,10 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
1125 atomic_inc(&ip_vs_nullsvc_counter); 1217 atomic_inc(&ip_vs_nullsvc_counter);
1126 1218
1127 ip_vs_new_estimator(&svc->stats); 1219 ip_vs_new_estimator(&svc->stats);
1128 ip_vs_num_services++; 1220
1221 /* Count only IPv4 services for old get/setsockopt interface */
1222 if (svc->af == AF_INET)
1223 ip_vs_num_services++;
1129 1224
1130 /* Hash the service into the service table */ 1225 /* Hash the service into the service table */
1131 write_lock_bh(&__ip_vs_svc_lock); 1226 write_lock_bh(&__ip_vs_svc_lock);
@@ -1160,7 +1255,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
1160 * Edit a service and bind it with a new scheduler 1255 * Edit a service and bind it with a new scheduler
1161 */ 1256 */
1162static int 1257static int
1163ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u) 1258ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
1164{ 1259{
1165 struct ip_vs_scheduler *sched, *old_sched; 1260 struct ip_vs_scheduler *sched, *old_sched;
1166 int ret = 0; 1261 int ret = 0;
@@ -1176,6 +1271,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u)
1176 } 1271 }
1177 old_sched = sched; 1272 old_sched = sched;
1178 1273
1274#ifdef CONFIG_IP_VS_IPV6
1275 if (u->af == AF_INET6) {
1276 if (!sched->supports_ipv6) {
1277 ret = -EAFNOSUPPORT;
1278 goto out;
1279 }
1280 if ((u->netmask < 1) || (u->netmask > 128)) {
1281 ret = -EINVAL;
1282 goto out;
1283 }
1284 }
1285#endif
1286
1179 write_lock_bh(&__ip_vs_svc_lock); 1287 write_lock_bh(&__ip_vs_svc_lock);
1180 1288
1181 /* 1289 /*
@@ -1240,7 +1348,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
1240 struct ip_vs_dest *dest, *nxt; 1348 struct ip_vs_dest *dest, *nxt;
1241 struct ip_vs_scheduler *old_sched; 1349 struct ip_vs_scheduler *old_sched;
1242 1350
1243 ip_vs_num_services--; 1351 /* Count only IPv4 services for old get/setsockopt interface */
1352 if (svc->af == AF_INET)
1353 ip_vs_num_services--;
1354
1244 ip_vs_kill_estimator(&svc->stats); 1355 ip_vs_kill_estimator(&svc->stats);
1245 1356
1246 /* Unbind scheduler */ 1357 /* Unbind scheduler */
@@ -1748,15 +1859,25 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
1748 const struct ip_vs_iter *iter = seq->private; 1859 const struct ip_vs_iter *iter = seq->private;
1749 const struct ip_vs_dest *dest; 1860 const struct ip_vs_dest *dest;
1750 1861
1751 if (iter->table == ip_vs_svc_table) 1862 if (iter->table == ip_vs_svc_table) {
1752 seq_printf(seq, "%s %08X:%04X %s ", 1863#ifdef CONFIG_IP_VS_IPV6
1753 ip_vs_proto_name(svc->protocol), 1864 if (svc->af == AF_INET6)
1754 ntohl(svc->addr), 1865 seq_printf(seq, "%s [" NIP6_FMT "]:%04X %s ",
1755 ntohs(svc->port), 1866 ip_vs_proto_name(svc->protocol),
1756 svc->scheduler->name); 1867 NIP6(svc->addr.in6),
1757 else 1868 ntohs(svc->port),
1869 svc->scheduler->name);
1870 else
1871#endif
1872 seq_printf(seq, "%s %08X:%04X %s ",
1873 ip_vs_proto_name(svc->protocol),
1874 ntohl(svc->addr.ip),
1875 ntohs(svc->port),
1876 svc->scheduler->name);
1877 } else {
1758 seq_printf(seq, "FWM %08X %s ", 1878 seq_printf(seq, "FWM %08X %s ",
1759 svc->fwmark, svc->scheduler->name); 1879 svc->fwmark, svc->scheduler->name);
1880 }
1760 1881
1761 if (svc->flags & IP_VS_SVC_F_PERSISTENT) 1882 if (svc->flags & IP_VS_SVC_F_PERSISTENT)
1762 seq_printf(seq, "persistent %d %08X\n", 1883 seq_printf(seq, "persistent %d %08X\n",
@@ -1766,13 +1887,29 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
1766 seq_putc(seq, '\n'); 1887 seq_putc(seq, '\n');
1767 1888
1768 list_for_each_entry(dest, &svc->destinations, n_list) { 1889 list_for_each_entry(dest, &svc->destinations, n_list) {
1769 seq_printf(seq, 1890#ifdef CONFIG_IP_VS_IPV6
1770 " -> %08X:%04X %-7s %-6d %-10d %-10d\n", 1891 if (dest->af == AF_INET6)
1771 ntohl(dest->addr), ntohs(dest->port), 1892 seq_printf(seq,
1772 ip_vs_fwd_name(atomic_read(&dest->conn_flags)), 1893 " -> [" NIP6_FMT "]:%04X"
1773 atomic_read(&dest->weight), 1894 " %-7s %-6d %-10d %-10d\n",
1774 atomic_read(&dest->activeconns), 1895 NIP6(dest->addr.in6),
1775 atomic_read(&dest->inactconns)); 1896 ntohs(dest->port),
1897 ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
1898 atomic_read(&dest->weight),
1899 atomic_read(&dest->activeconns),
1900 atomic_read(&dest->inactconns));
1901 else
1902#endif
1903 seq_printf(seq,
1904 " -> %08X:%04X "
1905 "%-7s %-6d %-10d %-10d\n",
1906 ntohl(dest->addr.ip),
1907 ntohs(dest->port),
1908 ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
1909 atomic_read(&dest->weight),
1910 atomic_read(&dest->activeconns),
1911 atomic_read(&dest->inactconns));
1912
1776 } 1913 }
1777 } 1914 }
1778 return 0; 1915 return 0;
@@ -1816,20 +1953,20 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v)
1816 " Conns Packets Packets Bytes Bytes\n"); 1953 " Conns Packets Packets Bytes Bytes\n");
1817 1954
1818 spin_lock_bh(&ip_vs_stats.lock); 1955 spin_lock_bh(&ip_vs_stats.lock);
1819 seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns, 1956 seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.ustats.conns,
1820 ip_vs_stats.inpkts, ip_vs_stats.outpkts, 1957 ip_vs_stats.ustats.inpkts, ip_vs_stats.ustats.outpkts,
1821 (unsigned long long) ip_vs_stats.inbytes, 1958 (unsigned long long) ip_vs_stats.ustats.inbytes,
1822 (unsigned long long) ip_vs_stats.outbytes); 1959 (unsigned long long) ip_vs_stats.ustats.outbytes);
1823 1960
1824/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ 1961/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */
1825 seq_puts(seq, 1962 seq_puts(seq,
1826 " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); 1963 " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n");
1827 seq_printf(seq,"%8X %8X %8X %16X %16X\n", 1964 seq_printf(seq,"%8X %8X %8X %16X %16X\n",
1828 ip_vs_stats.cps, 1965 ip_vs_stats.ustats.cps,
1829 ip_vs_stats.inpps, 1966 ip_vs_stats.ustats.inpps,
1830 ip_vs_stats.outpps, 1967 ip_vs_stats.ustats.outpps,
1831 ip_vs_stats.inbps, 1968 ip_vs_stats.ustats.inbps,
1832 ip_vs_stats.outbps); 1969 ip_vs_stats.ustats.outbps);
1833 spin_unlock_bh(&ip_vs_stats.lock); 1970 spin_unlock_bh(&ip_vs_stats.lock);
1834 1971
1835 return 0; 1972 return 0;
@@ -1904,14 +2041,44 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
1904 [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN, 2041 [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN,
1905}; 2042};
1906 2043
2044static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
2045 struct ip_vs_service_user *usvc_compat)
2046{
2047 usvc->af = AF_INET;
2048 usvc->protocol = usvc_compat->protocol;
2049 usvc->addr.ip = usvc_compat->addr;
2050 usvc->port = usvc_compat->port;
2051 usvc->fwmark = usvc_compat->fwmark;
2052
2053 /* Deep copy of sched_name is not needed here */
2054 usvc->sched_name = usvc_compat->sched_name;
2055
2056 usvc->flags = usvc_compat->flags;
2057 usvc->timeout = usvc_compat->timeout;
2058 usvc->netmask = usvc_compat->netmask;
2059}
2060
2061static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
2062 struct ip_vs_dest_user *udest_compat)
2063{
2064 udest->addr.ip = udest_compat->addr;
2065 udest->port = udest_compat->port;
2066 udest->conn_flags = udest_compat->conn_flags;
2067 udest->weight = udest_compat->weight;
2068 udest->u_threshold = udest_compat->u_threshold;
2069 udest->l_threshold = udest_compat->l_threshold;
2070}
2071
1907static int 2072static int
1908do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) 2073do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1909{ 2074{
1910 int ret; 2075 int ret;
1911 unsigned char arg[MAX_ARG_LEN]; 2076 unsigned char arg[MAX_ARG_LEN];
1912 struct ip_vs_service_user *usvc; 2077 struct ip_vs_service_user *usvc_compat;
2078 struct ip_vs_service_user_kern usvc;
1913 struct ip_vs_service *svc; 2079 struct ip_vs_service *svc;
1914 struct ip_vs_dest_user *udest; 2080 struct ip_vs_dest_user *udest_compat;
2081 struct ip_vs_dest_user_kern udest;
1915 2082
1916 if (!capable(CAP_NET_ADMIN)) 2083 if (!capable(CAP_NET_ADMIN))
1917 return -EPERM; 2084 return -EPERM;
@@ -1951,35 +2118,40 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1951 goto out_unlock; 2118 goto out_unlock;
1952 } 2119 }
1953 2120
1954 usvc = (struct ip_vs_service_user *)arg; 2121 usvc_compat = (struct ip_vs_service_user *)arg;
1955 udest = (struct ip_vs_dest_user *)(usvc + 1); 2122 udest_compat = (struct ip_vs_dest_user *)(usvc_compat + 1);
2123
2124 /* We only use the new structs internally, so copy userspace compat
2125 * structs to extended internal versions */
2126 ip_vs_copy_usvc_compat(&usvc, usvc_compat);
2127 ip_vs_copy_udest_compat(&udest, udest_compat);
1956 2128
1957 if (cmd == IP_VS_SO_SET_ZERO) { 2129 if (cmd == IP_VS_SO_SET_ZERO) {
1958 /* if no service address is set, zero counters in all */ 2130 /* if no service address is set, zero counters in all */
1959 if (!usvc->fwmark && !usvc->addr && !usvc->port) { 2131 if (!usvc.fwmark && !usvc.addr.ip && !usvc.port) {
1960 ret = ip_vs_zero_all(); 2132 ret = ip_vs_zero_all();
1961 goto out_unlock; 2133 goto out_unlock;
1962 } 2134 }
1963 } 2135 }
1964 2136
1965 /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ 2137 /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
1966 if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) { 2138 if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) {
1967 IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", 2139 IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
1968 usvc->protocol, NIPQUAD(usvc->addr), 2140 usvc.protocol, NIPQUAD(usvc.addr.ip),
1969 ntohs(usvc->port), usvc->sched_name); 2141 ntohs(usvc.port), usvc.sched_name);
1970 ret = -EFAULT; 2142 ret = -EFAULT;
1971 goto out_unlock; 2143 goto out_unlock;
1972 } 2144 }
1973 2145
1974 /* Lookup the exact service by <protocol, addr, port> or fwmark */ 2146 /* Lookup the exact service by <protocol, addr, port> or fwmark */
1975 if (usvc->fwmark == 0) 2147 if (usvc.fwmark == 0)
1976 svc = __ip_vs_service_get(usvc->protocol, 2148 svc = __ip_vs_service_get(usvc.af, usvc.protocol,
1977 usvc->addr, usvc->port); 2149 &usvc.addr, usvc.port);
1978 else 2150 else
1979 svc = __ip_vs_svc_fwm_get(usvc->fwmark); 2151 svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
1980 2152
1981 if (cmd != IP_VS_SO_SET_ADD 2153 if (cmd != IP_VS_SO_SET_ADD
1982 && (svc == NULL || svc->protocol != usvc->protocol)) { 2154 && (svc == NULL || svc->protocol != usvc.protocol)) {
1983 ret = -ESRCH; 2155 ret = -ESRCH;
1984 goto out_unlock; 2156 goto out_unlock;
1985 } 2157 }
@@ -1989,10 +2161,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1989 if (svc != NULL) 2161 if (svc != NULL)
1990 ret = -EEXIST; 2162 ret = -EEXIST;
1991 else 2163 else
1992 ret = ip_vs_add_service(usvc, &svc); 2164 ret = ip_vs_add_service(&usvc, &svc);
1993 break; 2165 break;
1994 case IP_VS_SO_SET_EDIT: 2166 case IP_VS_SO_SET_EDIT:
1995 ret = ip_vs_edit_service(svc, usvc); 2167 ret = ip_vs_edit_service(svc, &usvc);
1996 break; 2168 break;
1997 case IP_VS_SO_SET_DEL: 2169 case IP_VS_SO_SET_DEL:
1998 ret = ip_vs_del_service(svc); 2170 ret = ip_vs_del_service(svc);
@@ -2003,13 +2175,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2003 ret = ip_vs_zero_service(svc); 2175 ret = ip_vs_zero_service(svc);
2004 break; 2176 break;
2005 case IP_VS_SO_SET_ADDDEST: 2177 case IP_VS_SO_SET_ADDDEST:
2006 ret = ip_vs_add_dest(svc, udest); 2178 ret = ip_vs_add_dest(svc, &udest);
2007 break; 2179 break;
2008 case IP_VS_SO_SET_EDITDEST: 2180 case IP_VS_SO_SET_EDITDEST:
2009 ret = ip_vs_edit_dest(svc, udest); 2181 ret = ip_vs_edit_dest(svc, &udest);
2010 break; 2182 break;
2011 case IP_VS_SO_SET_DELDEST: 2183 case IP_VS_SO_SET_DELDEST:
2012 ret = ip_vs_del_dest(svc, udest); 2184 ret = ip_vs_del_dest(svc, &udest);
2013 break; 2185 break;
2014 default: 2186 default:
2015 ret = -EINVAL; 2187 ret = -EINVAL;
@@ -2032,7 +2204,7 @@ static void
2032ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) 2204ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
2033{ 2205{
2034 spin_lock_bh(&src->lock); 2206 spin_lock_bh(&src->lock);
2035 memcpy(dst, src, (char*)&src->lock - (char*)src); 2207 memcpy(dst, &src->ustats, sizeof(*dst));
2036 spin_unlock_bh(&src->lock); 2208 spin_unlock_bh(&src->lock);
2037} 2209}
2038 2210
@@ -2040,7 +2212,7 @@ static void
2040ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) 2212ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
2041{ 2213{
2042 dst->protocol = src->protocol; 2214 dst->protocol = src->protocol;
2043 dst->addr = src->addr; 2215 dst->addr = src->addr.ip;
2044 dst->port = src->port; 2216 dst->port = src->port;
2045 dst->fwmark = src->fwmark; 2217 dst->fwmark = src->fwmark;
2046 strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name)); 2218 strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
@@ -2062,6 +2234,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
2062 2234
2063 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 2235 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
2064 list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { 2236 list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
2237 /* Only expose IPv4 entries to old interface */
2238 if (svc->af != AF_INET)
2239 continue;
2240
2065 if (count >= get->num_services) 2241 if (count >= get->num_services)
2066 goto out; 2242 goto out;
2067 memset(&entry, 0, sizeof(entry)); 2243 memset(&entry, 0, sizeof(entry));
@@ -2077,6 +2253,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
2077 2253
2078 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 2254 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
2079 list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { 2255 list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
2256 /* Only expose IPv4 entries to old interface */
2257 if (svc->af != AF_INET)
2258 continue;
2259
2080 if (count >= get->num_services) 2260 if (count >= get->num_services)
2081 goto out; 2261 goto out;
2082 memset(&entry, 0, sizeof(entry)); 2262 memset(&entry, 0, sizeof(entry));
@@ -2098,13 +2278,15 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
2098 struct ip_vs_get_dests __user *uptr) 2278 struct ip_vs_get_dests __user *uptr)
2099{ 2279{
2100 struct ip_vs_service *svc; 2280 struct ip_vs_service *svc;
2281 union nf_inet_addr addr = { .ip = get->addr };
2101 int ret = 0; 2282 int ret = 0;
2102 2283
2103 if (get->fwmark) 2284 if (get->fwmark)
2104 svc = __ip_vs_svc_fwm_get(get->fwmark); 2285 svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark);
2105 else 2286 else
2106 svc = __ip_vs_service_get(get->protocol, 2287 svc = __ip_vs_service_get(AF_INET, get->protocol, &addr,
2107 get->addr, get->port); 2288 get->port);
2289
2108 if (svc) { 2290 if (svc) {
2109 int count = 0; 2291 int count = 0;
2110 struct ip_vs_dest *dest; 2292 struct ip_vs_dest *dest;
@@ -2114,7 +2296,7 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
2114 if (count >= get->num_dests) 2296 if (count >= get->num_dests)
2115 break; 2297 break;
2116 2298
2117 entry.addr = dest->addr; 2299 entry.addr = dest->addr.ip;
2118 entry.port = dest->port; 2300 entry.port = dest->port;
2119 entry.conn_flags = atomic_read(&dest->conn_flags); 2301 entry.conn_flags = atomic_read(&dest->conn_flags);
2120 entry.weight = atomic_read(&dest->weight); 2302 entry.weight = atomic_read(&dest->weight);
@@ -2239,13 +2421,15 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2239 { 2421 {
2240 struct ip_vs_service_entry *entry; 2422 struct ip_vs_service_entry *entry;
2241 struct ip_vs_service *svc; 2423 struct ip_vs_service *svc;
2424 union nf_inet_addr addr;
2242 2425
2243 entry = (struct ip_vs_service_entry *)arg; 2426 entry = (struct ip_vs_service_entry *)arg;
2427 addr.ip = entry->addr;
2244 if (entry->fwmark) 2428 if (entry->fwmark)
2245 svc = __ip_vs_svc_fwm_get(entry->fwmark); 2429 svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark);
2246 else 2430 else
2247 svc = __ip_vs_service_get(entry->protocol, 2431 svc = __ip_vs_service_get(AF_INET, entry->protocol,
2248 entry->addr, entry->port); 2432 &addr, entry->port);
2249 if (svc) { 2433 if (svc) {
2250 ip_vs_copy_service(entry, svc); 2434 ip_vs_copy_service(entry, svc);
2251 if (copy_to_user(user, entry, sizeof(*entry)) != 0) 2435 if (copy_to_user(user, entry, sizeof(*entry)) != 0)
@@ -2396,16 +2580,16 @@ static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
2396 2580
2397 spin_lock_bh(&stats->lock); 2581 spin_lock_bh(&stats->lock);
2398 2582
2399 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->conns); 2583 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns);
2400 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->inpkts); 2584 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts);
2401 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->outpkts); 2585 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts);
2402 NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->inbytes); 2586 NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes);
2403 NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->outbytes); 2587 NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes);
2404 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->cps); 2588 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps);
2405 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->inpps); 2589 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps);
2406 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->outpps); 2590 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps);
2407 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->inbps); 2591 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps);
2408 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->outbps); 2592 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps);
2409 2593
2410 spin_unlock_bh(&stats->lock); 2594 spin_unlock_bh(&stats->lock);
2411 2595
@@ -2430,7 +2614,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
2430 if (!nl_service) 2614 if (!nl_service)
2431 return -EMSGSIZE; 2615 return -EMSGSIZE;
2432 2616
2433 NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET); 2617 NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
2434 2618
2435 if (svc->fwmark) { 2619 if (svc->fwmark) {
2436 NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark); 2620 NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
@@ -2516,7 +2700,7 @@ nla_put_failure:
2516 return skb->len; 2700 return skb->len;
2517} 2701}
2518 2702
2519static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, 2703static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2520 struct nlattr *nla, int full_entry) 2704 struct nlattr *nla, int full_entry)
2521{ 2705{
2522 struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1]; 2706 struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
@@ -2536,8 +2720,12 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
2536 if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr)))) 2720 if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
2537 return -EINVAL; 2721 return -EINVAL;
2538 2722
2539 /* For now, only support IPv4 */ 2723 usvc->af = nla_get_u16(nla_af);
2540 if (nla_get_u16(nla_af) != AF_INET) 2724#ifdef CONFIG_IP_VS_IPV6
2725 if (usvc->af != AF_INET && usvc->af != AF_INET6)
2726#else
2727 if (usvc->af != AF_INET)
2728#endif
2541 return -EAFNOSUPPORT; 2729 return -EAFNOSUPPORT;
2542 2730
2543 if (nla_fwmark) { 2731 if (nla_fwmark) {
@@ -2569,10 +2757,10 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
2569 2757
2570 /* prefill flags from service if it already exists */ 2758 /* prefill flags from service if it already exists */
2571 if (usvc->fwmark) 2759 if (usvc->fwmark)
2572 svc = __ip_vs_svc_fwm_get(usvc->fwmark); 2760 svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark);
2573 else 2761 else
2574 svc = __ip_vs_service_get(usvc->protocol, usvc->addr, 2762 svc = __ip_vs_service_get(usvc->af, usvc->protocol,
2575 usvc->port); 2763 &usvc->addr, usvc->port);
2576 if (svc) { 2764 if (svc) {
2577 usvc->flags = svc->flags; 2765 usvc->flags = svc->flags;
2578 ip_vs_service_put(svc); 2766 ip_vs_service_put(svc);
@@ -2582,9 +2770,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
2582 /* set new flags from userland */ 2770 /* set new flags from userland */
2583 usvc->flags = (usvc->flags & ~flags.mask) | 2771 usvc->flags = (usvc->flags & ~flags.mask) |
2584 (flags.flags & flags.mask); 2772 (flags.flags & flags.mask);
2585 2773 usvc->sched_name = nla_data(nla_sched);
2586 strlcpy(usvc->sched_name, nla_data(nla_sched),
2587 sizeof(usvc->sched_name));
2588 usvc->timeout = nla_get_u32(nla_timeout); 2774 usvc->timeout = nla_get_u32(nla_timeout);
2589 usvc->netmask = nla_get_u32(nla_netmask); 2775 usvc->netmask = nla_get_u32(nla_netmask);
2590 } 2776 }
@@ -2594,7 +2780,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
2594 2780
2595static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) 2781static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
2596{ 2782{
2597 struct ip_vs_service_user usvc; 2783 struct ip_vs_service_user_kern usvc;
2598 int ret; 2784 int ret;
2599 2785
2600 ret = ip_vs_genl_parse_service(&usvc, nla, 0); 2786 ret = ip_vs_genl_parse_service(&usvc, nla, 0);
@@ -2602,10 +2788,10 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
2602 return ERR_PTR(ret); 2788 return ERR_PTR(ret);
2603 2789
2604 if (usvc.fwmark) 2790 if (usvc.fwmark)
2605 return __ip_vs_svc_fwm_get(usvc.fwmark); 2791 return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
2606 else 2792 else
2607 return __ip_vs_service_get(usvc.protocol, usvc.addr, 2793 return __ip_vs_service_get(usvc.af, usvc.protocol,
2608 usvc.port); 2794 &usvc.addr, usvc.port);
2609} 2795}
2610 2796
2611static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) 2797static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
@@ -2704,7 +2890,7 @@ out_err:
2704 return skb->len; 2890 return skb->len;
2705} 2891}
2706 2892
2707static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest, 2893static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
2708 struct nlattr *nla, int full_entry) 2894 struct nlattr *nla, int full_entry)
2709{ 2895{
2710 struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; 2896 struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
@@ -2860,8 +3046,8 @@ static int ip_vs_genl_set_config(struct nlattr **attrs)
2860static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) 3046static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
2861{ 3047{
2862 struct ip_vs_service *svc = NULL; 3048 struct ip_vs_service *svc = NULL;
2863 struct ip_vs_service_user usvc; 3049 struct ip_vs_service_user_kern usvc;
2864 struct ip_vs_dest_user udest; 3050 struct ip_vs_dest_user_kern udest;
2865 int ret = 0, cmd; 3051 int ret = 0, cmd;
2866 int need_full_svc = 0, need_full_dest = 0; 3052 int need_full_svc = 0, need_full_dest = 0;
2867 3053
@@ -2913,9 +3099,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
2913 3099
2914 /* Lookup the exact service by <protocol, addr, port> or fwmark */ 3100 /* Lookup the exact service by <protocol, addr, port> or fwmark */
2915 if (usvc.fwmark == 0) 3101 if (usvc.fwmark == 0)
2916 svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port); 3102 svc = __ip_vs_service_get(usvc.af, usvc.protocol,
3103 &usvc.addr, usvc.port);
2917 else 3104 else
2918 svc = __ip_vs_svc_fwm_get(usvc.fwmark); 3105 svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
2919 3106
2920 /* Unless we're adding a new service, the service must already exist */ 3107 /* Unless we're adding a new service, the service must already exist */
2921 if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) { 3108 if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index fa66824d264f..a16943fd72f1 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -218,7 +218,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
218 IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u " 218 IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
219 "--> server %u.%u.%u.%u:%d\n", 219 "--> server %u.%u.%u.%u:%d\n",
220 NIPQUAD(iph->daddr), 220 NIPQUAD(iph->daddr),
221 NIPQUAD(dest->addr), 221 NIPQUAD(dest->addr.ip),
222 ntohs(dest->port)); 222 ntohs(dest->port));
223 223
224 return dest; 224 return dest;
@@ -234,6 +234,9 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
234 .refcnt = ATOMIC_INIT(0), 234 .refcnt = ATOMIC_INIT(0),
235 .module = THIS_MODULE, 235 .module = THIS_MODULE,
236 .n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list), 236 .n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
237#ifdef CONFIG_IP_VS_IPV6
238 .supports_ipv6 = 0,
239#endif
237 .init_service = ip_vs_dh_init_svc, 240 .init_service = ip_vs_dh_init_svc,
238 .done_service = ip_vs_dh_done_svc, 241 .done_service = ip_vs_dh_done_svc,
239 .update_service = ip_vs_dh_update_svc, 242 .update_service = ip_vs_dh_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
index 4fb620ec2086..2eb2860dabb5 100644
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ b/net/ipv4/ipvs/ip_vs_est.c
@@ -65,37 +65,37 @@ static void estimation_timer(unsigned long arg)
65 s = container_of(e, struct ip_vs_stats, est); 65 s = container_of(e, struct ip_vs_stats, est);
66 66
67 spin_lock(&s->lock); 67 spin_lock(&s->lock);
68 n_conns = s->conns; 68 n_conns = s->ustats.conns;
69 n_inpkts = s->inpkts; 69 n_inpkts = s->ustats.inpkts;
70 n_outpkts = s->outpkts; 70 n_outpkts = s->ustats.outpkts;
71 n_inbytes = s->inbytes; 71 n_inbytes = s->ustats.inbytes;
72 n_outbytes = s->outbytes; 72 n_outbytes = s->ustats.outbytes;
73 73
74 /* scaled by 2^10, but divided 2 seconds */ 74 /* scaled by 2^10, but divided 2 seconds */
75 rate = (n_conns - e->last_conns)<<9; 75 rate = (n_conns - e->last_conns)<<9;
76 e->last_conns = n_conns; 76 e->last_conns = n_conns;
77 e->cps += ((long)rate - (long)e->cps)>>2; 77 e->cps += ((long)rate - (long)e->cps)>>2;
78 s->cps = (e->cps+0x1FF)>>10; 78 s->ustats.cps = (e->cps+0x1FF)>>10;
79 79
80 rate = (n_inpkts - e->last_inpkts)<<9; 80 rate = (n_inpkts - e->last_inpkts)<<9;
81 e->last_inpkts = n_inpkts; 81 e->last_inpkts = n_inpkts;
82 e->inpps += ((long)rate - (long)e->inpps)>>2; 82 e->inpps += ((long)rate - (long)e->inpps)>>2;
83 s->inpps = (e->inpps+0x1FF)>>10; 83 s->ustats.inpps = (e->inpps+0x1FF)>>10;
84 84
85 rate = (n_outpkts - e->last_outpkts)<<9; 85 rate = (n_outpkts - e->last_outpkts)<<9;
86 e->last_outpkts = n_outpkts; 86 e->last_outpkts = n_outpkts;
87 e->outpps += ((long)rate - (long)e->outpps)>>2; 87 e->outpps += ((long)rate - (long)e->outpps)>>2;
88 s->outpps = (e->outpps+0x1FF)>>10; 88 s->ustats.outpps = (e->outpps+0x1FF)>>10;
89 89
90 rate = (n_inbytes - e->last_inbytes)<<4; 90 rate = (n_inbytes - e->last_inbytes)<<4;
91 e->last_inbytes = n_inbytes; 91 e->last_inbytes = n_inbytes;
92 e->inbps += ((long)rate - (long)e->inbps)>>2; 92 e->inbps += ((long)rate - (long)e->inbps)>>2;
93 s->inbps = (e->inbps+0xF)>>5; 93 s->ustats.inbps = (e->inbps+0xF)>>5;
94 94
95 rate = (n_outbytes - e->last_outbytes)<<4; 95 rate = (n_outbytes - e->last_outbytes)<<4;
96 e->last_outbytes = n_outbytes; 96 e->last_outbytes = n_outbytes;
97 e->outbps += ((long)rate - (long)e->outbps)>>2; 97 e->outbps += ((long)rate - (long)e->outbps)>>2;
98 s->outbps = (e->outbps+0xF)>>5; 98 s->ustats.outbps = (e->outbps+0xF)>>5;
99 spin_unlock(&s->lock); 99 spin_unlock(&s->lock);
100 } 100 }
101 spin_unlock(&est_lock); 101 spin_unlock(&est_lock);
@@ -108,20 +108,20 @@ void ip_vs_new_estimator(struct ip_vs_stats *stats)
108 108
109 INIT_LIST_HEAD(&est->list); 109 INIT_LIST_HEAD(&est->list);
110 110
111 est->last_conns = stats->conns; 111 est->last_conns = stats->ustats.conns;
112 est->cps = stats->cps<<10; 112 est->cps = stats->ustats.cps<<10;
113 113
114 est->last_inpkts = stats->inpkts; 114 est->last_inpkts = stats->ustats.inpkts;
115 est->inpps = stats->inpps<<10; 115 est->inpps = stats->ustats.inpps<<10;
116 116
117 est->last_outpkts = stats->outpkts; 117 est->last_outpkts = stats->ustats.outpkts;
118 est->outpps = stats->outpps<<10; 118 est->outpps = stats->ustats.outpps<<10;
119 119
120 est->last_inbytes = stats->inbytes; 120 est->last_inbytes = stats->ustats.inbytes;
121 est->inbps = stats->inbps<<5; 121 est->inbps = stats->ustats.inbps<<5;
122 122
123 est->last_outbytes = stats->outbytes; 123 est->last_outbytes = stats->ustats.outbytes;
124 est->outbps = stats->outbps<<5; 124 est->outbps = stats->ustats.outbps<<5;
125 125
126 spin_lock_bh(&est_lock); 126 spin_lock_bh(&est_lock);
127 list_add(&est->list, &est_list); 127 list_add(&est->list, &est_list);
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index c1c758e4f733..2e7dbd8b73a4 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -140,13 +140,21 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
140 struct tcphdr *th; 140 struct tcphdr *th;
141 char *data, *data_limit; 141 char *data, *data_limit;
142 char *start, *end; 142 char *start, *end;
143 __be32 from; 143 union nf_inet_addr from;
144 __be16 port; 144 __be16 port;
145 struct ip_vs_conn *n_cp; 145 struct ip_vs_conn *n_cp;
146 char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ 146 char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
147 unsigned buf_len; 147 unsigned buf_len;
148 int ret; 148 int ret;
149 149
150#ifdef CONFIG_IP_VS_IPV6
151 /* This application helper doesn't work with IPv6 yet,
152 * so turn this into a no-op for IPv6 packets
153 */
154 if (cp->af == AF_INET6)
155 return 1;
156#endif
157
150 *diff = 0; 158 *diff = 0;
151 159
152 /* Only useful for established sessions */ 160 /* Only useful for established sessions */
@@ -166,24 +174,25 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
166 if (ip_vs_ftp_get_addrport(data, data_limit, 174 if (ip_vs_ftp_get_addrport(data, data_limit,
167 SERVER_STRING, 175 SERVER_STRING,
168 sizeof(SERVER_STRING)-1, ')', 176 sizeof(SERVER_STRING)-1, ')',
169 &from, &port, 177 &from.ip, &port,
170 &start, &end) != 1) 178 &start, &end) != 1)
171 return 1; 179 return 1;
172 180
173 IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> " 181 IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
174 "%u.%u.%u.%u:%d detected\n", 182 "%u.%u.%u.%u:%d detected\n",
175 NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0); 183 NIPQUAD(from.ip), ntohs(port),
184 NIPQUAD(cp->caddr.ip), 0);
176 185
177 /* 186 /*
178 * Now update or create an connection entry for it 187 * Now update or create an connection entry for it
179 */ 188 */
180 n_cp = ip_vs_conn_out_get(iph->protocol, from, port, 189 n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
181 cp->caddr, 0); 190 &cp->caddr, 0);
182 if (!n_cp) { 191 if (!n_cp) {
183 n_cp = ip_vs_conn_new(IPPROTO_TCP, 192 n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
184 cp->caddr, 0, 193 &cp->caddr, 0,
185 cp->vaddr, port, 194 &cp->vaddr, port,
186 from, port, 195 &from, port,
187 IP_VS_CONN_F_NO_CPORT, 196 IP_VS_CONN_F_NO_CPORT,
188 cp->dest); 197 cp->dest);
189 if (!n_cp) 198 if (!n_cp)
@@ -196,9 +205,9 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
196 /* 205 /*
197 * Replace the old passive address with the new one 206 * Replace the old passive address with the new one
198 */ 207 */
199 from = n_cp->vaddr; 208 from.ip = n_cp->vaddr.ip;
200 port = n_cp->vport; 209 port = n_cp->vport;
201 sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from), 210 sprintf(buf, "%d,%d,%d,%d,%d,%d", NIPQUAD(from.ip),
202 (ntohs(port)>>8)&255, ntohs(port)&255); 211 (ntohs(port)>>8)&255, ntohs(port)&255);
203 buf_len = strlen(buf); 212 buf_len = strlen(buf);
204 213
@@ -243,10 +252,18 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
243 struct tcphdr *th; 252 struct tcphdr *th;
244 char *data, *data_start, *data_limit; 253 char *data, *data_start, *data_limit;
245 char *start, *end; 254 char *start, *end;
246 __be32 to; 255 union nf_inet_addr to;
247 __be16 port; 256 __be16 port;
248 struct ip_vs_conn *n_cp; 257 struct ip_vs_conn *n_cp;
249 258
259#ifdef CONFIG_IP_VS_IPV6
260 /* This application helper doesn't work with IPv6 yet,
261 * so turn this into a no-op for IPv6 packets
262 */
263 if (cp->af == AF_INET6)
264 return 1;
265#endif
266
250 /* no diff required for incoming packets */ 267 /* no diff required for incoming packets */
251 *diff = 0; 268 *diff = 0;
252 269
@@ -291,12 +308,12 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
291 */ 308 */
292 if (ip_vs_ftp_get_addrport(data_start, data_limit, 309 if (ip_vs_ftp_get_addrport(data_start, data_limit,
293 CLIENT_STRING, sizeof(CLIENT_STRING)-1, 310 CLIENT_STRING, sizeof(CLIENT_STRING)-1,
294 '\r', &to, &port, 311 '\r', &to.ip, &port,
295 &start, &end) != 1) 312 &start, &end) != 1)
296 return 1; 313 return 1;
297 314
298 IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n", 315 IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n",
299 NIPQUAD(to), ntohs(port)); 316 NIPQUAD(to.ip), ntohs(port));
300 317
301 /* Passive mode off */ 318 /* Passive mode off */
302 cp->app_data = NULL; 319 cp->app_data = NULL;
@@ -306,16 +323,16 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
306 */ 323 */
307 IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n", 324 IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
308 ip_vs_proto_name(iph->protocol), 325 ip_vs_proto_name(iph->protocol),
309 NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr), 0); 326 NIPQUAD(to.ip), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
310 327
311 n_cp = ip_vs_conn_in_get(iph->protocol, 328 n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
312 to, port, 329 &to, port,
313 cp->vaddr, htons(ntohs(cp->vport)-1)); 330 &cp->vaddr, htons(ntohs(cp->vport)-1));
314 if (!n_cp) { 331 if (!n_cp) {
315 n_cp = ip_vs_conn_new(IPPROTO_TCP, 332 n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
316 to, port, 333 &to, port,
317 cp->vaddr, htons(ntohs(cp->vport)-1), 334 &cp->vaddr, htons(ntohs(cp->vport)-1),
318 cp->daddr, htons(ntohs(cp->dport)-1), 335 &cp->daddr, htons(ntohs(cp->dport)-1),
319 0, 336 0,
320 cp->dest); 337 cp->dest);
321 if (!n_cp) 338 if (!n_cp)
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index d2a43aa3fe4c..6ecef3518cac 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -422,7 +422,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
422 422
423 IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d " 423 IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
424 "activeconns %d refcnt %d weight %d overhead %d\n", 424 "activeconns %d refcnt %d weight %d overhead %d\n",
425 NIPQUAD(least->addr), ntohs(least->port), 425 NIPQUAD(least->addr.ip), ntohs(least->port),
426 atomic_read(&least->activeconns), 426 atomic_read(&least->activeconns),
427 atomic_read(&least->refcnt), 427 atomic_read(&least->refcnt),
428 atomic_read(&least->weight), loh); 428 atomic_read(&least->weight), loh);
@@ -506,7 +506,7 @@ out:
506 IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u " 506 IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
507 "--> server %u.%u.%u.%u:%d\n", 507 "--> server %u.%u.%u.%u:%d\n",
508 NIPQUAD(iph->daddr), 508 NIPQUAD(iph->daddr),
509 NIPQUAD(dest->addr), 509 NIPQUAD(dest->addr.ip),
510 ntohs(dest->port)); 510 ntohs(dest->port));
511 511
512 return dest; 512 return dest;
@@ -522,6 +522,9 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler =
522 .refcnt = ATOMIC_INIT(0), 522 .refcnt = ATOMIC_INIT(0),
523 .module = THIS_MODULE, 523 .module = THIS_MODULE,
524 .n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list), 524 .n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
525#ifdef CONFIG_IP_VS_IPV6
526 .supports_ipv6 = 0,
527#endif
525 .init_service = ip_vs_lblc_init_svc, 528 .init_service = ip_vs_lblc_init_svc,
526 .done_service = ip_vs_lblc_done_svc, 529 .done_service = ip_vs_lblc_done_svc,
527 .schedule = ip_vs_lblc_schedule, 530 .schedule = ip_vs_lblc_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 375a1ffb6b65..1f75ea83bcf8 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -204,7 +204,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
204 204
205 IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d " 205 IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
206 "activeconns %d refcnt %d weight %d overhead %d\n", 206 "activeconns %d refcnt %d weight %d overhead %d\n",
207 NIPQUAD(least->addr), ntohs(least->port), 207 NIPQUAD(least->addr.ip), ntohs(least->port),
208 atomic_read(&least->activeconns), 208 atomic_read(&least->activeconns),
209 atomic_read(&least->refcnt), 209 atomic_read(&least->refcnt),
210 atomic_read(&least->weight), loh); 210 atomic_read(&least->weight), loh);
@@ -250,7 +250,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
250 250
251 IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d " 251 IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
252 "activeconns %d refcnt %d weight %d overhead %d\n", 252 "activeconns %d refcnt %d weight %d overhead %d\n",
253 NIPQUAD(most->addr), ntohs(most->port), 253 NIPQUAD(most->addr.ip), ntohs(most->port),
254 atomic_read(&most->activeconns), 254 atomic_read(&most->activeconns),
255 atomic_read(&most->refcnt), 255 atomic_read(&most->refcnt),
256 atomic_read(&most->weight), moh); 256 atomic_read(&most->weight), moh);
@@ -598,7 +598,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
598 598
599 IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d " 599 IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
600 "activeconns %d refcnt %d weight %d overhead %d\n", 600 "activeconns %d refcnt %d weight %d overhead %d\n",
601 NIPQUAD(least->addr), ntohs(least->port), 601 NIPQUAD(least->addr.ip), ntohs(least->port),
602 atomic_read(&least->activeconns), 602 atomic_read(&least->activeconns),
603 atomic_read(&least->refcnt), 603 atomic_read(&least->refcnt),
604 atomic_read(&least->weight), loh); 604 atomic_read(&least->weight), loh);
@@ -706,7 +706,7 @@ out:
706 IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u " 706 IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
707 "--> server %u.%u.%u.%u:%d\n", 707 "--> server %u.%u.%u.%u:%d\n",
708 NIPQUAD(iph->daddr), 708 NIPQUAD(iph->daddr),
709 NIPQUAD(dest->addr), 709 NIPQUAD(dest->addr.ip),
710 ntohs(dest->port)); 710 ntohs(dest->port));
711 711
712 return dest; 712 return dest;
@@ -722,6 +722,9 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
722 .refcnt = ATOMIC_INIT(0), 722 .refcnt = ATOMIC_INIT(0),
723 .module = THIS_MODULE, 723 .module = THIS_MODULE,
724 .n_list = LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list), 724 .n_list = LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
725#ifdef CONFIG_IP_VS_IPV6
726 .supports_ipv6 = 0,
727#endif
725 .init_service = ip_vs_lblcr_init_svc, 728 .init_service = ip_vs_lblcr_init_svc,
726 .done_service = ip_vs_lblcr_done_svc, 729 .done_service = ip_vs_lblcr_done_svc,
727 .schedule = ip_vs_lblcr_schedule, 730 .schedule = ip_vs_lblcr_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index 2c3de1b63518..b69f808ac461 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -67,10 +67,10 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
67 } 67 }
68 68
69 if (least) 69 if (least)
70 IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n", 70 IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d inactconns %d\n",
71 NIPQUAD(least->addr), ntohs(least->port), 71 IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
72 atomic_read(&least->activeconns), 72 atomic_read(&least->activeconns),
73 atomic_read(&least->inactconns)); 73 atomic_read(&least->inactconns));
74 74
75 return least; 75 return least;
76} 76}
@@ -81,6 +81,9 @@ static struct ip_vs_scheduler ip_vs_lc_scheduler = {
81 .refcnt = ATOMIC_INIT(0), 81 .refcnt = ATOMIC_INIT(0),
82 .module = THIS_MODULE, 82 .module = THIS_MODULE,
83 .n_list = LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list), 83 .n_list = LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
84#ifdef CONFIG_IP_VS_IPV6
85 .supports_ipv6 = 1,
86#endif
84 .schedule = ip_vs_lc_schedule, 87 .schedule = ip_vs_lc_schedule,
85}; 88};
86 89
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index 5330d5a2de14..9a2d8033f08f 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -99,12 +99,12 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
99 return NULL; 99 return NULL;
100 100
101 out: 101 out:
102 IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u " 102 IP_VS_DBG_BUF(6, "NQ: server %s:%u "
103 "activeconns %d refcnt %d weight %d overhead %d\n", 103 "activeconns %d refcnt %d weight %d overhead %d\n",
104 NIPQUAD(least->addr), ntohs(least->port), 104 IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
105 atomic_read(&least->activeconns), 105 atomic_read(&least->activeconns),
106 atomic_read(&least->refcnt), 106 atomic_read(&least->refcnt),
107 atomic_read(&least->weight), loh); 107 atomic_read(&least->weight), loh);
108 108
109 return least; 109 return least;
110} 110}
@@ -116,6 +116,9 @@ static struct ip_vs_scheduler ip_vs_nq_scheduler =
116 .refcnt = ATOMIC_INIT(0), 116 .refcnt = ATOMIC_INIT(0),
117 .module = THIS_MODULE, 117 .module = THIS_MODULE,
118 .n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list), 118 .n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
119#ifdef CONFIG_IP_VS_IPV6
120 .supports_ipv6 = 1,
121#endif
119 .schedule = ip_vs_nq_schedule, 122 .schedule = ip_vs_nq_schedule,
120}; 123};
121 124
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 6099a88fc200..b06da1c3445a 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -151,11 +151,11 @@ const char * ip_vs_state_name(__u16 proto, int state)
151} 151}
152 152
153 153
154void 154static void
155ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp, 155ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
156 const struct sk_buff *skb, 156 const struct sk_buff *skb,
157 int offset, 157 int offset,
158 const char *msg) 158 const char *msg)
159{ 159{
160 char buf[128]; 160 char buf[128];
161 struct iphdr _iph, *ih; 161 struct iphdr _iph, *ih;
@@ -189,6 +189,61 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
189 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); 189 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
190} 190}
191 191
192#ifdef CONFIG_IP_VS_IPV6
193static void
194ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
195 const struct sk_buff *skb,
196 int offset,
197 const char *msg)
198{
199 char buf[192];
200 struct ipv6hdr _iph, *ih;
201
202 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
203 if (ih == NULL)
204 sprintf(buf, "%s TRUNCATED", pp->name);
205 else if (ih->nexthdr == IPPROTO_FRAGMENT)
206 sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT " frag",
207 pp->name, NIP6(ih->saddr),
208 NIP6(ih->daddr));
209 else {
210 __be16 _ports[2], *pptr;
211
212 pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
213 sizeof(_ports), _ports);
214 if (pptr == NULL)
215 sprintf(buf, "%s TRUNCATED " NIP6_FMT "->" NIP6_FMT,
216 pp->name,
217 NIP6(ih->saddr),
218 NIP6(ih->daddr));
219 else
220 sprintf(buf, "%s " NIP6_FMT ":%u->" NIP6_FMT ":%u",
221 pp->name,
222 NIP6(ih->saddr),
223 ntohs(pptr[0]),
224 NIP6(ih->daddr),
225 ntohs(pptr[1]));
226 }
227
228 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
229}
230#endif
231
232
233void
234ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
235 const struct sk_buff *skb,
236 int offset,
237 const char *msg)
238{
239#ifdef CONFIG_IP_VS_IPV6
240 if (skb->protocol == __constant_htons(ETH_P_IPV6))
241 ip_vs_tcpudp_debug_packet_v6(pp, skb, offset, msg);
242 else
243#endif
244 ip_vs_tcpudp_debug_packet_v4(pp, skb, offset, msg);
245}
246
192 247
193int __init ip_vs_protocol_init(void) 248int __init ip_vs_protocol_init(void)
194{ 249{
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
index 3f9ebd7639ae..2b18a78d0399 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(af, IPPROTO_UDP,
52 iph->saddr, 50 &iph->saddr,
53 htons(PORT_ISAKMP), 51 htons(PORT_ISAKMP),
54 iph->daddr, 52 &iph->daddr,
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(af, IPPROTO_UDP,
58 iph->daddr, 56 &iph->daddr,
59 htons(PORT_ISAKMP), 57 htons(PORT_ISAKMP),
60 iph->saddr, 58 &iph->saddr,
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(af, IPPROTO_UDP,
89 iph->saddr, 90 &iph->saddr,
90 htons(PORT_ISAKMP), 91 htons(PORT_ISAKMP),
91 iph->daddr, 92 &iph->daddr,
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(af, IPPROTO_UDP,
95 iph->daddr, 96 &iph->daddr,
96 htons(PORT_ISAKMP), 97 htons(PORT_ISAKMP),
97 iph->saddr, 98 &iph->saddr,
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 /*
@@ -125,8 +125,8 @@ ah_esp_conn_schedule(struct sk_buff *skb,
125 125
126 126
127static void 127static void
128ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, 128ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
129 int offset, const char *msg) 129 int offset, const char *msg)
130{ 130{
131 char buf[256]; 131 char buf[256];
132 struct iphdr _iph, *ih; 132 struct iphdr _iph, *ih;
@@ -142,6 +142,38 @@ ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
142 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); 142 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
143} 143}
144 144
145#ifdef CONFIG_IP_VS_IPV6
146static void
147ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
148 int offset, const char *msg)
149{
150 char buf[256];
151 struct ipv6hdr _iph, *ih;
152
153 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
154 if (ih == NULL)
155 sprintf(buf, "%s TRUNCATED", pp->name);
156 else
157 sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT,
158 pp->name, NIP6(ih->saddr),
159 NIP6(ih->daddr));
160
161 printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
162}
163#endif
164
165static void
166ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
167 int offset, const char *msg)
168{
169#ifdef CONFIG_IP_VS_IPV6
170 if (skb->protocol == __constant_htons(ETH_P_IPV6))
171 ah_esp_debug_packet_v6(pp, skb, offset, msg);
172 else
173#endif
174 ah_esp_debug_packet_v4(pp, skb, offset, msg);
175}
176
145 177
146static void ah_esp_init(struct ip_vs_protocol *pp) 178static void ah_esp_init(struct ip_vs_protocol *pp)
147{ 179{
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index d0ea467986a0..537f616776da 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
@@ -35,19 +36,20 @@ tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
35 return NULL; 36 return NULL;
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(af, iph->protocol,
39 iph->saddr, pptr[0], 40 &iph->saddr, pptr[0],
40 iph->daddr, pptr[1]); 41 &iph->daddr, pptr[1]);
41 } else { 42 } else {
42 return ip_vs_conn_in_get(iph->protocol, 43 return ip_vs_conn_in_get(af, iph->protocol,
43 iph->daddr, pptr[1], 44 &iph->daddr, pptr[1],
44 iph->saddr, pptr[0]); 45 &iph->saddr, 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
@@ -56,34 +58,36 @@ tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
56 return NULL; 58 return NULL;
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(af, iph->protocol,
60 iph->saddr, pptr[0], 62 &iph->saddr, pptr[0],
61 iph->daddr, pptr[1]); 63 &iph->daddr, pptr[1]);
62 } else { 64 } else {
63 return ip_vs_conn_out_get(iph->protocol, 65 return ip_vs_conn_out_get(af, iph->protocol,
64 iph->daddr, pptr[1], 66 &iph->daddr, pptr[1],
65 iph->saddr, pptr[0]); 67 &iph->saddr, 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;
78 struct ip_vs_iphdr iph;
77 79
78 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 80 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
81
82 th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
79 if (th == NULL) { 83 if (th == NULL) {
80 *verdict = NF_DROP; 84 *verdict = NF_DROP;
81 return 0; 85 return 0;
82 } 86 }
83 87
84 if (th->syn && 88 if (th->syn &&
85 (svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol, 89 (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
86 ip_hdr(skb)->daddr, th->dest))) { 90 th->dest))) {
87 if (ip_vs_todrop()) { 91 if (ip_vs_todrop()) {
88 /* 92 /*
89 * It seems that we are very loaded. 93 * It seems that we are very loaded.
@@ -110,22 +114,62 @@ tcp_conn_schedule(struct sk_buff *skb,
110 114
111 115
112static inline void 116static inline void
113tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip, 117tcp_fast_csum_update(int af, struct tcphdr *tcph,
118 const union nf_inet_addr *oldip,
119 const union nf_inet_addr *newip,
114 __be16 oldport, __be16 newport) 120 __be16 oldport, __be16 newport)
115{ 121{
122#ifdef CONFIG_IP_VS_IPV6
123 if (af == AF_INET6)
124 tcph->check =
125 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
126 ip_vs_check_diff2(oldport, newport,
127 ~csum_unfold(tcph->check))));
128 else
129#endif
116 tcph->check = 130 tcph->check =
117 csum_fold(ip_vs_check_diff4(oldip, newip, 131 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
118 ip_vs_check_diff2(oldport, newport, 132 ip_vs_check_diff2(oldport, newport,
119 ~csum_unfold(tcph->check)))); 133 ~csum_unfold(tcph->check))));
120} 134}
121 135
122 136
137static inline void
138tcp_partial_csum_update(int af, struct tcphdr *tcph,
139 const union nf_inet_addr *oldip,
140 const union nf_inet_addr *newip,
141 __be16 oldlen, __be16 newlen)
142{
143#ifdef CONFIG_IP_VS_IPV6
144 if (af == AF_INET6)
145 tcph->check =
146 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
147 ip_vs_check_diff2(oldlen, newlen,
148 ~csum_unfold(tcph->check))));
149 else
150#endif
151 tcph->check =
152 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
153 ip_vs_check_diff2(oldlen, newlen,
154 ~csum_unfold(tcph->check))));
155}
156
157
123static int 158static int
124tcp_snat_handler(struct sk_buff *skb, 159tcp_snat_handler(struct sk_buff *skb,
125 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 160 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
126{ 161{
127 struct tcphdr *tcph; 162 struct tcphdr *tcph;
128 const unsigned int tcphoff = ip_hdrlen(skb); 163 unsigned int tcphoff;
164 int oldlen;
165
166#ifdef CONFIG_IP_VS_IPV6
167 if (cp->af == AF_INET6)
168 tcphoff = sizeof(struct ipv6hdr);
169 else
170#endif
171 tcphoff = ip_hdrlen(skb);
172 oldlen = skb->len - tcphoff;
129 173
130 /* csum_check requires unshared skb */ 174 /* csum_check requires unshared skb */
131 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph))) 175 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -133,7 +177,7 @@ tcp_snat_handler(struct sk_buff *skb,
133 177
134 if (unlikely(cp->app != NULL)) { 178 if (unlikely(cp->app != NULL)) {
135 /* Some checks before mangling */ 179 /* Some checks before mangling */
136 if (pp->csum_check && !pp->csum_check(skb, pp)) 180 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
137 return 0; 181 return 0;
138 182
139 /* Call application helper if needed */ 183 /* Call application helper if needed */
@@ -141,13 +185,17 @@ tcp_snat_handler(struct sk_buff *skb,
141 return 0; 185 return 0;
142 } 186 }
143 187
144 tcph = (void *)ip_hdr(skb) + tcphoff; 188 tcph = (void *)skb_network_header(skb) + tcphoff;
145 tcph->source = cp->vport; 189 tcph->source = cp->vport;
146 190
147 /* Adjust TCP checksums */ 191 /* Adjust TCP checksums */
148 if (!cp->app) { 192 if (skb->ip_summed == CHECKSUM_PARTIAL) {
193 tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
194 htonl(oldlen),
195 htonl(skb->len - tcphoff));
196 } else if (!cp->app) {
149 /* Only port and addr are changed, do fast csum update */ 197 /* Only port and addr are changed, do fast csum update */
150 tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr, 198 tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
151 cp->dport, cp->vport); 199 cp->dport, cp->vport);
152 if (skb->ip_summed == CHECKSUM_COMPLETE) 200 if (skb->ip_summed == CHECKSUM_COMPLETE)
153 skb->ip_summed = CHECKSUM_NONE; 201 skb->ip_summed = CHECKSUM_NONE;
@@ -155,9 +203,20 @@ tcp_snat_handler(struct sk_buff *skb,
155 /* full checksum calculation */ 203 /* full checksum calculation */
156 tcph->check = 0; 204 tcph->check = 0;
157 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 205 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
158 tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr, 206#ifdef CONFIG_IP_VS_IPV6
159 skb->len - tcphoff, 207 if (cp->af == AF_INET6)
160 cp->protocol, skb->csum); 208 tcph->check = csum_ipv6_magic(&cp->vaddr.in6,
209 &cp->caddr.in6,
210 skb->len - tcphoff,
211 cp->protocol, skb->csum);
212 else
213#endif
214 tcph->check = csum_tcpudp_magic(cp->vaddr.ip,
215 cp->caddr.ip,
216 skb->len - tcphoff,
217 cp->protocol,
218 skb->csum);
219
161 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", 220 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
162 pp->name, tcph->check, 221 pp->name, tcph->check,
163 (char*)&(tcph->check) - (char*)tcph); 222 (char*)&(tcph->check) - (char*)tcph);
@@ -171,7 +230,16 @@ tcp_dnat_handler(struct sk_buff *skb,
171 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 230 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
172{ 231{
173 struct tcphdr *tcph; 232 struct tcphdr *tcph;
174 const unsigned int tcphoff = ip_hdrlen(skb); 233 unsigned int tcphoff;
234 int oldlen;
235
236#ifdef CONFIG_IP_VS_IPV6
237 if (cp->af == AF_INET6)
238 tcphoff = sizeof(struct ipv6hdr);
239 else
240#endif
241 tcphoff = ip_hdrlen(skb);
242 oldlen = skb->len - tcphoff;
175 243
176 /* csum_check requires unshared skb */ 244 /* csum_check requires unshared skb */
177 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph))) 245 if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -179,7 +247,7 @@ tcp_dnat_handler(struct sk_buff *skb,
179 247
180 if (unlikely(cp->app != NULL)) { 248 if (unlikely(cp->app != NULL)) {
181 /* Some checks before mangling */ 249 /* Some checks before mangling */
182 if (pp->csum_check && !pp->csum_check(skb, pp)) 250 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
183 return 0; 251 return 0;
184 252
185 /* 253 /*
@@ -190,15 +258,19 @@ tcp_dnat_handler(struct sk_buff *skb,
190 return 0; 258 return 0;
191 } 259 }
192 260
193 tcph = (void *)ip_hdr(skb) + tcphoff; 261 tcph = (void *)skb_network_header(skb) + tcphoff;
194 tcph->dest = cp->dport; 262 tcph->dest = cp->dport;
195 263
196 /* 264 /*
197 * Adjust TCP checksums 265 * Adjust TCP checksums
198 */ 266 */
199 if (!cp->app) { 267 if (skb->ip_summed == CHECKSUM_PARTIAL) {
268 tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
269 htonl(oldlen),
270 htonl(skb->len - tcphoff));
271 } else if (!cp->app) {
200 /* Only port and addr are changed, do fast csum update */ 272 /* Only port and addr are changed, do fast csum update */
201 tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr, 273 tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
202 cp->vport, cp->dport); 274 cp->vport, cp->dport);
203 if (skb->ip_summed == CHECKSUM_COMPLETE) 275 if (skb->ip_summed == CHECKSUM_COMPLETE)
204 skb->ip_summed = CHECKSUM_NONE; 276 skb->ip_summed = CHECKSUM_NONE;
@@ -206,9 +278,19 @@ tcp_dnat_handler(struct sk_buff *skb,
206 /* full checksum calculation */ 278 /* full checksum calculation */
207 tcph->check = 0; 279 tcph->check = 0;
208 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 280 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
209 tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr, 281#ifdef CONFIG_IP_VS_IPV6
210 skb->len - tcphoff, 282 if (cp->af == AF_INET6)
211 cp->protocol, skb->csum); 283 tcph->check = csum_ipv6_magic(&cp->caddr.in6,
284 &cp->daddr.in6,
285 skb->len - tcphoff,
286 cp->protocol, skb->csum);
287 else
288#endif
289 tcph->check = csum_tcpudp_magic(cp->caddr.ip,
290 cp->daddr.ip,
291 skb->len - tcphoff,
292 cp->protocol,
293 skb->csum);
212 skb->ip_summed = CHECKSUM_UNNECESSARY; 294 skb->ip_summed = CHECKSUM_UNNECESSARY;
213 } 295 }
214 return 1; 296 return 1;
@@ -216,21 +298,43 @@ tcp_dnat_handler(struct sk_buff *skb,
216 298
217 299
218static int 300static int
219tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) 301tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
220{ 302{
221 const unsigned int tcphoff = ip_hdrlen(skb); 303 unsigned int tcphoff;
304
305#ifdef CONFIG_IP_VS_IPV6
306 if (af == AF_INET6)
307 tcphoff = sizeof(struct ipv6hdr);
308 else
309#endif
310 tcphoff = ip_hdrlen(skb);
222 311
223 switch (skb->ip_summed) { 312 switch (skb->ip_summed) {
224 case CHECKSUM_NONE: 313 case CHECKSUM_NONE:
225 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); 314 skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
226 case CHECKSUM_COMPLETE: 315 case CHECKSUM_COMPLETE:
227 if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 316#ifdef CONFIG_IP_VS_IPV6
228 skb->len - tcphoff, 317 if (af == AF_INET6) {
229 ip_hdr(skb)->protocol, skb->csum)) { 318 if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
230 IP_VS_DBG_RL_PKT(0, pp, skb, 0, 319 &ipv6_hdr(skb)->daddr,
231 "Failed checksum for"); 320 skb->len - tcphoff,
232 return 0; 321 ipv6_hdr(skb)->nexthdr,
233 } 322 skb->csum)) {
323 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
324 "Failed checksum for");
325 return 0;
326 }
327 } else
328#endif
329 if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
330 ip_hdr(skb)->daddr,
331 skb->len - tcphoff,
332 ip_hdr(skb)->protocol,
333 skb->csum)) {
334 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
335 "Failed checksum for");
336 return 0;
337 }
234 break; 338 break;
235 default: 339 default:
236 /* No need to checksum. */ 340 /* No need to checksum. */
@@ -419,19 +523,23 @@ set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
419 if (new_state != cp->state) { 523 if (new_state != cp->state) {
420 struct ip_vs_dest *dest = cp->dest; 524 struct ip_vs_dest *dest = cp->dest;
421 525
422 IP_VS_DBG(8, "%s %s [%c%c%c%c] %u.%u.%u.%u:%d->" 526 IP_VS_DBG_BUF(8, "%s %s [%c%c%c%c] %s:%d->"
423 "%u.%u.%u.%u:%d state: %s->%s conn->refcnt:%d\n", 527 "%s:%d state: %s->%s conn->refcnt:%d\n",
424 pp->name, 528 pp->name,
425 (state_off==TCP_DIR_OUTPUT)?"output ":"input ", 529 ((state_off == TCP_DIR_OUTPUT) ?
426 th->syn? 'S' : '.', 530 "output " : "input "),
427 th->fin? 'F' : '.', 531 th->syn ? 'S' : '.',
428 th->ack? 'A' : '.', 532 th->fin ? 'F' : '.',
429 th->rst? 'R' : '.', 533 th->ack ? 'A' : '.',
430 NIPQUAD(cp->daddr), ntohs(cp->dport), 534 th->rst ? 'R' : '.',
431 NIPQUAD(cp->caddr), ntohs(cp->cport), 535 IP_VS_DBG_ADDR(cp->af, &cp->daddr),
432 tcp_state_name(cp->state), 536 ntohs(cp->dport),
433 tcp_state_name(new_state), 537 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
434 atomic_read(&cp->refcnt)); 538 ntohs(cp->cport),
539 tcp_state_name(cp->state),
540 tcp_state_name(new_state),
541 atomic_read(&cp->refcnt));
542
435 if (dest) { 543 if (dest) {
436 if (!(cp->flags & IP_VS_CONN_F_INACTIVE) && 544 if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
437 (new_state != IP_VS_TCP_S_ESTABLISHED)) { 545 (new_state != IP_VS_TCP_S_ESTABLISHED)) {
@@ -461,7 +569,13 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
461{ 569{
462 struct tcphdr _tcph, *th; 570 struct tcphdr _tcph, *th;
463 571
464 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 572#ifdef CONFIG_IP_VS_IPV6
573 int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
574#else
575 int ihl = ip_hdrlen(skb);
576#endif
577
578 th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);
465 if (th == NULL) 579 if (th == NULL)
466 return 0; 580 return 0;
467 581
@@ -546,12 +660,15 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
546 break; 660 break;
547 spin_unlock(&tcp_app_lock); 661 spin_unlock(&tcp_app_lock);
548 662
549 IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->" 663 IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
550 "%u.%u.%u.%u:%u to app %s on port %u\n", 664 "%s:%u to app %s on port %u\n",
551 __func__, 665 __func__,
552 NIPQUAD(cp->caddr), ntohs(cp->cport), 666 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
553 NIPQUAD(cp->vaddr), ntohs(cp->vport), 667 ntohs(cp->cport),
554 inc->name, ntohs(inc->port)); 668 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
669 ntohs(cp->vport),
670 inc->name, ntohs(inc->port));
671
555 cp->app = inc; 672 cp->app = inc;
556 if (inc->init_conn) 673 if (inc->init_conn)
557 result = inc->init_conn(inc, cp); 674 result = inc->init_conn(inc, cp);
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index c6be5d56823f..e3ee26bd1de7 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;
@@ -35,13 +36,13 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
35 return NULL; 36 return NULL;
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(af, iph->protocol,
39 iph->saddr, pptr[0], 40 &iph->saddr, pptr[0],
40 iph->daddr, pptr[1]); 41 &iph->daddr, pptr[1]);
41 } else { 42 } else {
42 cp = ip_vs_conn_in_get(iph->protocol, 43 cp = ip_vs_conn_in_get(af, iph->protocol,
43 iph->daddr, pptr[1], 44 &iph->daddr, pptr[1],
44 iph->saddr, pptr[0]); 45 &iph->saddr, 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(af, iph->protocol,
65 iph->saddr, pptr[0], 66 &iph->saddr, pptr[0],
66 iph->daddr, pptr[1]); 67 &iph->daddr, pptr[1]);
67 } else { 68 } else {
68 cp = ip_vs_conn_out_get(iph->protocol, 69 cp = ip_vs_conn_out_get(af, iph->protocol,
69 iph->daddr, pptr[1], 70 &iph->daddr, pptr[1],
70 iph->saddr, pptr[0]); 71 &iph->saddr, pptr[0]);
71 } 72 }
72 73
73 return cp; 74 return cp;
@@ -75,21 +76,24 @@ 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;
84 struct ip_vs_iphdr iph;
85
86 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
83 87
84 uh = skb_header_pointer(skb, ip_hdrlen(skb), 88 uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
85 sizeof(_udph), &_udph);
86 if (uh == NULL) { 89 if (uh == NULL) {
87 *verdict = NF_DROP; 90 *verdict = NF_DROP;
88 return 0; 91 return 0;
89 } 92 }
90 93
91 if ((svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol, 94 svc = ip_vs_service_get(af, skb->mark, iph.protocol,
92 ip_hdr(skb)->daddr, uh->dest))) { 95 &iph.daddr, uh->dest);
96 if (svc) {
93 if (ip_vs_todrop()) { 97 if (ip_vs_todrop()) {
94 /* 98 /*
95 * It seems that we are very loaded. 99 * It seems that we are very loaded.
@@ -116,23 +120,63 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
116 120
117 121
118static inline void 122static inline void
119udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip, 123udp_fast_csum_update(int af, struct udphdr *uhdr,
124 const union nf_inet_addr *oldip,
125 const union nf_inet_addr *newip,
120 __be16 oldport, __be16 newport) 126 __be16 oldport, __be16 newport)
121{ 127{
122 uhdr->check = 128#ifdef CONFIG_IP_VS_IPV6
123 csum_fold(ip_vs_check_diff4(oldip, newip, 129 if (af == AF_INET6)
124 ip_vs_check_diff2(oldport, newport, 130 uhdr->check =
125 ~csum_unfold(uhdr->check)))); 131 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
132 ip_vs_check_diff2(oldport, newport,
133 ~csum_unfold(uhdr->check))));
134 else
135#endif
136 uhdr->check =
137 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
138 ip_vs_check_diff2(oldport, newport,
139 ~csum_unfold(uhdr->check))));
126 if (!uhdr->check) 140 if (!uhdr->check)
127 uhdr->check = CSUM_MANGLED_0; 141 uhdr->check = CSUM_MANGLED_0;
128} 142}
129 143
144static inline void
145udp_partial_csum_update(int af, struct udphdr *uhdr,
146 const union nf_inet_addr *oldip,
147 const union nf_inet_addr *newip,
148 __be16 oldlen, __be16 newlen)
149{
150#ifdef CONFIG_IP_VS_IPV6
151 if (af == AF_INET6)
152 uhdr->check =
153 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
154 ip_vs_check_diff2(oldlen, newlen,
155 ~csum_unfold(uhdr->check))));
156 else
157#endif
158 uhdr->check =
159 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
160 ip_vs_check_diff2(oldlen, newlen,
161 ~csum_unfold(uhdr->check))));
162}
163
164
130static int 165static int
131udp_snat_handler(struct sk_buff *skb, 166udp_snat_handler(struct sk_buff *skb,
132 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 167 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
133{ 168{
134 struct udphdr *udph; 169 struct udphdr *udph;
135 const unsigned int udphoff = ip_hdrlen(skb); 170 unsigned int udphoff;
171 int oldlen;
172
173#ifdef CONFIG_IP_VS_IPV6
174 if (cp->af == AF_INET6)
175 udphoff = sizeof(struct ipv6hdr);
176 else
177#endif
178 udphoff = ip_hdrlen(skb);
179 oldlen = skb->len - udphoff;
136 180
137 /* csum_check requires unshared skb */ 181 /* csum_check requires unshared skb */
138 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 182 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -140,7 +184,7 @@ udp_snat_handler(struct sk_buff *skb,
140 184
141 if (unlikely(cp->app != NULL)) { 185 if (unlikely(cp->app != NULL)) {
142 /* Some checks before mangling */ 186 /* Some checks before mangling */
143 if (pp->csum_check && !pp->csum_check(skb, pp)) 187 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
144 return 0; 188 return 0;
145 189
146 /* 190 /*
@@ -150,15 +194,19 @@ udp_snat_handler(struct sk_buff *skb,
150 return 0; 194 return 0;
151 } 195 }
152 196
153 udph = (void *)ip_hdr(skb) + udphoff; 197 udph = (void *)skb_network_header(skb) + udphoff;
154 udph->source = cp->vport; 198 udph->source = cp->vport;
155 199
156 /* 200 /*
157 * Adjust UDP checksums 201 * Adjust UDP checksums
158 */ 202 */
159 if (!cp->app && (udph->check != 0)) { 203 if (skb->ip_summed == CHECKSUM_PARTIAL) {
204 udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
205 htonl(oldlen),
206 htonl(skb->len - udphoff));
207 } else if (!cp->app && (udph->check != 0)) {
160 /* Only port and addr are changed, do fast csum update */ 208 /* Only port and addr are changed, do fast csum update */
161 udp_fast_csum_update(udph, cp->daddr, cp->vaddr, 209 udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
162 cp->dport, cp->vport); 210 cp->dport, cp->vport);
163 if (skb->ip_summed == CHECKSUM_COMPLETE) 211 if (skb->ip_summed == CHECKSUM_COMPLETE)
164 skb->ip_summed = CHECKSUM_NONE; 212 skb->ip_summed = CHECKSUM_NONE;
@@ -166,9 +214,19 @@ udp_snat_handler(struct sk_buff *skb,
166 /* full checksum calculation */ 214 /* full checksum calculation */
167 udph->check = 0; 215 udph->check = 0;
168 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0); 216 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
169 udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr, 217#ifdef CONFIG_IP_VS_IPV6
170 skb->len - udphoff, 218 if (cp->af == AF_INET6)
171 cp->protocol, skb->csum); 219 udph->check = csum_ipv6_magic(&cp->vaddr.in6,
220 &cp->caddr.in6,
221 skb->len - udphoff,
222 cp->protocol, skb->csum);
223 else
224#endif
225 udph->check = csum_tcpudp_magic(cp->vaddr.ip,
226 cp->caddr.ip,
227 skb->len - udphoff,
228 cp->protocol,
229 skb->csum);
172 if (udph->check == 0) 230 if (udph->check == 0)
173 udph->check = CSUM_MANGLED_0; 231 udph->check = CSUM_MANGLED_0;
174 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n", 232 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
@@ -184,7 +242,16 @@ udp_dnat_handler(struct sk_buff *skb,
184 struct ip_vs_protocol *pp, struct ip_vs_conn *cp) 242 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
185{ 243{
186 struct udphdr *udph; 244 struct udphdr *udph;
187 unsigned int udphoff = ip_hdrlen(skb); 245 unsigned int udphoff;
246 int oldlen;
247
248#ifdef CONFIG_IP_VS_IPV6
249 if (cp->af == AF_INET6)
250 udphoff = sizeof(struct ipv6hdr);
251 else
252#endif
253 udphoff = ip_hdrlen(skb);
254 oldlen = skb->len - udphoff;
188 255
189 /* csum_check requires unshared skb */ 256 /* csum_check requires unshared skb */
190 if (!skb_make_writable(skb, udphoff+sizeof(*udph))) 257 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -192,7 +259,7 @@ udp_dnat_handler(struct sk_buff *skb,
192 259
193 if (unlikely(cp->app != NULL)) { 260 if (unlikely(cp->app != NULL)) {
194 /* Some checks before mangling */ 261 /* Some checks before mangling */
195 if (pp->csum_check && !pp->csum_check(skb, pp)) 262 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
196 return 0; 263 return 0;
197 264
198 /* 265 /*
@@ -203,15 +270,19 @@ udp_dnat_handler(struct sk_buff *skb,
203 return 0; 270 return 0;
204 } 271 }
205 272
206 udph = (void *)ip_hdr(skb) + udphoff; 273 udph = (void *)skb_network_header(skb) + udphoff;
207 udph->dest = cp->dport; 274 udph->dest = cp->dport;
208 275
209 /* 276 /*
210 * Adjust UDP checksums 277 * Adjust UDP checksums
211 */ 278 */
212 if (!cp->app && (udph->check != 0)) { 279 if (skb->ip_summed == CHECKSUM_PARTIAL) {
280 udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
281 htonl(oldlen),
282 htonl(skb->len - udphoff));
283 } else if (!cp->app && (udph->check != 0)) {
213 /* Only port and addr are changed, do fast csum update */ 284 /* Only port and addr are changed, do fast csum update */
214 udp_fast_csum_update(udph, cp->vaddr, cp->daddr, 285 udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
215 cp->vport, cp->dport); 286 cp->vport, cp->dport);
216 if (skb->ip_summed == CHECKSUM_COMPLETE) 287 if (skb->ip_summed == CHECKSUM_COMPLETE)
217 skb->ip_summed = CHECKSUM_NONE; 288 skb->ip_summed = CHECKSUM_NONE;
@@ -219,9 +290,19 @@ udp_dnat_handler(struct sk_buff *skb,
219 /* full checksum calculation */ 290 /* full checksum calculation */
220 udph->check = 0; 291 udph->check = 0;
221 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0); 292 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
222 udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr, 293#ifdef CONFIG_IP_VS_IPV6
223 skb->len - udphoff, 294 if (cp->af == AF_INET6)
224 cp->protocol, skb->csum); 295 udph->check = csum_ipv6_magic(&cp->caddr.in6,
296 &cp->daddr.in6,
297 skb->len - udphoff,
298 cp->protocol, skb->csum);
299 else
300#endif
301 udph->check = csum_tcpudp_magic(cp->caddr.ip,
302 cp->daddr.ip,
303 skb->len - udphoff,
304 cp->protocol,
305 skb->csum);
225 if (udph->check == 0) 306 if (udph->check == 0)
226 udph->check = CSUM_MANGLED_0; 307 udph->check = CSUM_MANGLED_0;
227 skb->ip_summed = CHECKSUM_UNNECESSARY; 308 skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -231,10 +312,17 @@ udp_dnat_handler(struct sk_buff *skb,
231 312
232 313
233static int 314static int
234udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) 315udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
235{ 316{
236 struct udphdr _udph, *uh; 317 struct udphdr _udph, *uh;
237 const unsigned int udphoff = ip_hdrlen(skb); 318 unsigned int udphoff;
319
320#ifdef CONFIG_IP_VS_IPV6
321 if (af == AF_INET6)
322 udphoff = sizeof(struct ipv6hdr);
323 else
324#endif
325 udphoff = ip_hdrlen(skb);
238 326
239 uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph); 327 uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
240 if (uh == NULL) 328 if (uh == NULL)
@@ -246,15 +334,28 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
246 skb->csum = skb_checksum(skb, udphoff, 334 skb->csum = skb_checksum(skb, udphoff,
247 skb->len - udphoff, 0); 335 skb->len - udphoff, 0);
248 case CHECKSUM_COMPLETE: 336 case CHECKSUM_COMPLETE:
249 if (csum_tcpudp_magic(ip_hdr(skb)->saddr, 337#ifdef CONFIG_IP_VS_IPV6
250 ip_hdr(skb)->daddr, 338 if (af == AF_INET6) {
251 skb->len - udphoff, 339 if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
252 ip_hdr(skb)->protocol, 340 &ipv6_hdr(skb)->daddr,
253 skb->csum)) { 341 skb->len - udphoff,
254 IP_VS_DBG_RL_PKT(0, pp, skb, 0, 342 ipv6_hdr(skb)->nexthdr,
255 "Failed checksum for"); 343 skb->csum)) {
256 return 0; 344 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
257 } 345 "Failed checksum for");
346 return 0;
347 }
348 } else
349#endif
350 if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
351 ip_hdr(skb)->daddr,
352 skb->len - udphoff,
353 ip_hdr(skb)->protocol,
354 skb->csum)) {
355 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
356 "Failed checksum for");
357 return 0;
358 }
258 break; 359 break;
259 default: 360 default:
260 /* No need to checksum. */ 361 /* No need to checksum. */
@@ -340,12 +441,15 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
340 break; 441 break;
341 spin_unlock(&udp_app_lock); 442 spin_unlock(&udp_app_lock);
342 443
343 IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->" 444 IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
344 "%u.%u.%u.%u:%u to app %s on port %u\n", 445 "%s:%u to app %s on port %u\n",
345 __func__, 446 __func__,
346 NIPQUAD(cp->caddr), ntohs(cp->cport), 447 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
347 NIPQUAD(cp->vaddr), ntohs(cp->vport), 448 ntohs(cp->cport),
348 inc->name, ntohs(inc->port)); 449 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
450 ntohs(cp->vport),
451 inc->name, ntohs(inc->port));
452
349 cp->app = inc; 453 cp->app = inc;
350 if (inc->init_conn) 454 if (inc->init_conn)
351 result = inc->init_conn(inc, cp); 455 result = inc->init_conn(inc, cp);
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index f74929117534..a22195f68ac4 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -74,11 +74,11 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
74 out: 74 out:
75 svc->sched_data = q; 75 svc->sched_data = q;
76 write_unlock(&svc->sched_lock); 76 write_unlock(&svc->sched_lock);
77 IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u " 77 IP_VS_DBG_BUF(6, "RR: server %s:%u "
78 "activeconns %d refcnt %d weight %d\n", 78 "activeconns %d refcnt %d weight %d\n",
79 NIPQUAD(dest->addr), ntohs(dest->port), 79 IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
80 atomic_read(&dest->activeconns), 80 atomic_read(&dest->activeconns),
81 atomic_read(&dest->refcnt), atomic_read(&dest->weight)); 81 atomic_read(&dest->refcnt), atomic_read(&dest->weight));
82 82
83 return dest; 83 return dest;
84} 84}
@@ -89,6 +89,9 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = {
89 .refcnt = ATOMIC_INIT(0), 89 .refcnt = ATOMIC_INIT(0),
90 .module = THIS_MODULE, 90 .module = THIS_MODULE,
91 .n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list), 91 .n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
92#ifdef CONFIG_IP_VS_IPV6
93 .supports_ipv6 = 1,
94#endif
92 .init_service = ip_vs_rr_init_svc, 95 .init_service = ip_vs_rr_init_svc,
93 .update_service = ip_vs_rr_update_svc, 96 .update_service = ip_vs_rr_update_svc,
94 .schedule = ip_vs_rr_schedule, 97 .schedule = ip_vs_rr_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 53f73bea66ce..7d2f22f04b83 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -101,12 +101,12 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
101 } 101 }
102 } 102 }
103 103
104 IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u " 104 IP_VS_DBG_BUF(6, "SED: server %s:%u "
105 "activeconns %d refcnt %d weight %d overhead %d\n", 105 "activeconns %d refcnt %d weight %d overhead %d\n",
106 NIPQUAD(least->addr), ntohs(least->port), 106 IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
107 atomic_read(&least->activeconns), 107 atomic_read(&least->activeconns),
108 atomic_read(&least->refcnt), 108 atomic_read(&least->refcnt),
109 atomic_read(&least->weight), loh); 109 atomic_read(&least->weight), loh);
110 110
111 return least; 111 return least;
112} 112}
@@ -118,6 +118,9 @@ static struct ip_vs_scheduler ip_vs_sed_scheduler =
118 .refcnt = ATOMIC_INIT(0), 118 .refcnt = ATOMIC_INIT(0),
119 .module = THIS_MODULE, 119 .module = THIS_MODULE,
120 .n_list = LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list), 120 .n_list = LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
121#ifdef CONFIG_IP_VS_IPV6
122 .supports_ipv6 = 1,
123#endif
121 .schedule = ip_vs_sed_schedule, 124 .schedule = ip_vs_sed_schedule,
122}; 125};
123 126
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 7b979e228056..1d96de27fefd 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -215,7 +215,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
215 IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u " 215 IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
216 "--> server %u.%u.%u.%u:%d\n", 216 "--> server %u.%u.%u.%u:%d\n",
217 NIPQUAD(iph->saddr), 217 NIPQUAD(iph->saddr),
218 NIPQUAD(dest->addr), 218 NIPQUAD(dest->addr.ip),
219 ntohs(dest->port)); 219 ntohs(dest->port));
220 220
221 return dest; 221 return dest;
@@ -231,6 +231,9 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler =
231 .refcnt = ATOMIC_INIT(0), 231 .refcnt = ATOMIC_INIT(0),
232 .module = THIS_MODULE, 232 .module = THIS_MODULE,
233 .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list), 233 .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
234#ifdef CONFIG_IP_VS_IPV6
235 .supports_ipv6 = 0,
236#endif
234 .init_service = ip_vs_sh_init_svc, 237 .init_service = ip_vs_sh_init_svc,
235 .done_service = ip_vs_sh_done_svc, 238 .done_service = ip_vs_sh_done_svc,
236 .update_service = ip_vs_sh_update_svc, 239 .update_service = ip_vs_sh_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index a652da2c3200..28237a5f62e2 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -256,9 +256,9 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp)
256 s->cport = cp->cport; 256 s->cport = cp->cport;
257 s->vport = cp->vport; 257 s->vport = cp->vport;
258 s->dport = cp->dport; 258 s->dport = cp->dport;
259 s->caddr = cp->caddr; 259 s->caddr = cp->caddr.ip;
260 s->vaddr = cp->vaddr; 260 s->vaddr = cp->vaddr.ip;
261 s->daddr = cp->daddr; 261 s->daddr = cp->daddr.ip;
262 s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED); 262 s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
263 s->state = htons(cp->state); 263 s->state = htons(cp->state);
264 if (cp->flags & IP_VS_CONN_F_SEQ_MASK) { 264 if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
@@ -366,21 +366,28 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
366 } 366 }
367 367
368 if (!(flags & IP_VS_CONN_F_TEMPLATE)) 368 if (!(flags & IP_VS_CONN_F_TEMPLATE))
369 cp = ip_vs_conn_in_get(s->protocol, 369 cp = ip_vs_conn_in_get(AF_INET, s->protocol,
370 s->caddr, s->cport, 370 (union nf_inet_addr *)&s->caddr,
371 s->vaddr, s->vport); 371 s->cport,
372 (union nf_inet_addr *)&s->vaddr,
373 s->vport);
372 else 374 else
373 cp = ip_vs_ct_in_get(s->protocol, 375 cp = ip_vs_ct_in_get(AF_INET, s->protocol,
374 s->caddr, s->cport, 376 (union nf_inet_addr *)&s->caddr,
375 s->vaddr, s->vport); 377 s->cport,
378 (union nf_inet_addr *)&s->vaddr,
379 s->vport);
376 if (!cp) { 380 if (!cp) {
377 /* 381 /*
378 * Find the appropriate destination for the connection. 382 * Find the appropriate destination for the connection.
379 * If it is not found the connection will remain unbound 383 * If it is not found the connection will remain unbound
380 * but still handled. 384 * but still handled.
381 */ 385 */
382 dest = ip_vs_find_dest(s->daddr, s->dport, 386 dest = ip_vs_find_dest(AF_INET,
383 s->vaddr, s->vport, 387 (union nf_inet_addr *)&s->daddr,
388 s->dport,
389 (union nf_inet_addr *)&s->vaddr,
390 s->vport,
384 s->protocol); 391 s->protocol);
385 /* Set the approprite ativity flag */ 392 /* Set the approprite ativity flag */
386 if (s->protocol == IPPROTO_TCP) { 393 if (s->protocol == IPPROTO_TCP) {
@@ -389,10 +396,13 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
389 else 396 else
390 flags &= ~IP_VS_CONN_F_INACTIVE; 397 flags &= ~IP_VS_CONN_F_INACTIVE;
391 } 398 }
392 cp = ip_vs_conn_new(s->protocol, 399 cp = ip_vs_conn_new(AF_INET, s->protocol,
393 s->caddr, s->cport, 400 (union nf_inet_addr *)&s->caddr,
394 s->vaddr, s->vport, 401 s->cport,
395 s->daddr, s->dport, 402 (union nf_inet_addr *)&s->vaddr,
403 s->vport,
404 (union nf_inet_addr *)&s->daddr,
405 s->dport,
396 flags, dest); 406 flags, dest);
397 if (dest) 407 if (dest)
398 atomic_dec(&dest->refcnt); 408 atomic_dec(&dest->refcnt);
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index df7ad8d74766..8c596e712599 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -89,12 +89,12 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
89 } 89 }
90 } 90 }
91 91
92 IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u " 92 IP_VS_DBG_BUF(6, "WLC: server %s:%u "
93 "activeconns %d refcnt %d weight %d overhead %d\n", 93 "activeconns %d refcnt %d weight %d overhead %d\n",
94 NIPQUAD(least->addr), ntohs(least->port), 94 IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
95 atomic_read(&least->activeconns), 95 atomic_read(&least->activeconns),
96 atomic_read(&least->refcnt), 96 atomic_read(&least->refcnt),
97 atomic_read(&least->weight), loh); 97 atomic_read(&least->weight), loh);
98 98
99 return least; 99 return least;
100} 100}
@@ -106,6 +106,9 @@ static struct ip_vs_scheduler ip_vs_wlc_scheduler =
106 .refcnt = ATOMIC_INIT(0), 106 .refcnt = ATOMIC_INIT(0),
107 .module = THIS_MODULE, 107 .module = THIS_MODULE,
108 .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list), 108 .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
109#ifdef CONFIG_IP_VS_IPV6
110 .supports_ipv6 = 1,
111#endif
109 .schedule = ip_vs_wlc_schedule, 112 .schedule = ip_vs_wlc_schedule,
110}; 113};
111 114
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 0d86a79b87b5..7ea92fed50bf 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -195,12 +195,12 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
195 } 195 }
196 } 196 }
197 197
198 IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u " 198 IP_VS_DBG_BUF(6, "WRR: server %s:%u "
199 "activeconns %d refcnt %d weight %d\n", 199 "activeconns %d refcnt %d weight %d\n",
200 NIPQUAD(dest->addr), ntohs(dest->port), 200 IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
201 atomic_read(&dest->activeconns), 201 atomic_read(&dest->activeconns),
202 atomic_read(&dest->refcnt), 202 atomic_read(&dest->refcnt),
203 atomic_read(&dest->weight)); 203 atomic_read(&dest->weight));
204 204
205 out: 205 out:
206 write_unlock(&svc->sched_lock); 206 write_unlock(&svc->sched_lock);
@@ -213,6 +213,9 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
213 .refcnt = ATOMIC_INIT(0), 213 .refcnt = ATOMIC_INIT(0),
214 .module = THIS_MODULE, 214 .module = THIS_MODULE,
215 .n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list), 215 .n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
216#ifdef CONFIG_IP_VS_IPV6
217 .supports_ipv6 = 1,
218#endif
216 .init_service = ip_vs_wrr_init_svc, 219 .init_service = ip_vs_wrr_init_svc,
217 .done_service = ip_vs_wrr_done_svc, 220 .done_service = ip_vs_wrr_done_svc,
218 .update_service = ip_vs_wrr_update_svc, 221 .update_service = ip_vs_wrr_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 9892d4aca42e..02ddc2b3ce2e 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -20,6 +20,9 @@
20#include <net/udp.h> 20#include <net/udp.h>
21#include <net/icmp.h> /* for icmp_send */ 21#include <net/icmp.h> /* for icmp_send */
22#include <net/route.h> /* for ip_route_output */ 22#include <net/route.h> /* for ip_route_output */
23#include <net/ipv6.h>
24#include <net/ip6_route.h>
25#include <linux/icmpv6.h>
23#include <linux/netfilter.h> 26#include <linux/netfilter.h>
24#include <linux/netfilter_ipv4.h> 27#include <linux/netfilter_ipv4.h>
25 28
@@ -47,7 +50,8 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
47 50
48 if (!dst) 51 if (!dst)
49 return NULL; 52 return NULL;
50 if ((dst->obsolete || rtos != dest->dst_rtos) && 53 if ((dst->obsolete
54 || (dest->af == AF_INET && rtos != dest->dst_rtos)) &&
51 dst->ops->check(dst, cookie) == NULL) { 55 dst->ops->check(dst, cookie) == NULL) {
52 dest->dst_cache = NULL; 56 dest->dst_cache = NULL;
53 dst_release(dst); 57 dst_release(dst);
@@ -71,7 +75,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
71 .oif = 0, 75 .oif = 0,
72 .nl_u = { 76 .nl_u = {
73 .ip4_u = { 77 .ip4_u = {
74 .daddr = dest->addr, 78 .daddr = dest->addr.ip,
75 .saddr = 0, 79 .saddr = 0,
76 .tos = rtos, } }, 80 .tos = rtos, } },
77 }; 81 };
@@ -80,12 +84,12 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
80 spin_unlock(&dest->dst_lock); 84 spin_unlock(&dest->dst_lock);
81 IP_VS_DBG_RL("ip_route_output error, " 85 IP_VS_DBG_RL("ip_route_output error, "
82 "dest: %u.%u.%u.%u\n", 86 "dest: %u.%u.%u.%u\n",
83 NIPQUAD(dest->addr)); 87 NIPQUAD(dest->addr.ip));
84 return NULL; 88 return NULL;
85 } 89 }
86 __ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst)); 90 __ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
87 IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n", 91 IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
88 NIPQUAD(dest->addr), 92 NIPQUAD(dest->addr.ip),
89 atomic_read(&rt->u.dst.__refcnt), rtos); 93 atomic_read(&rt->u.dst.__refcnt), rtos);
90 } 94 }
91 spin_unlock(&dest->dst_lock); 95 spin_unlock(&dest->dst_lock);
@@ -94,14 +98,14 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
94 .oif = 0, 98 .oif = 0,
95 .nl_u = { 99 .nl_u = {
96 .ip4_u = { 100 .ip4_u = {
97 .daddr = cp->daddr, 101 .daddr = cp->daddr.ip,
98 .saddr = 0, 102 .saddr = 0,
99 .tos = rtos, } }, 103 .tos = rtos, } },
100 }; 104 };
101 105
102 if (ip_route_output_key(&init_net, &rt, &fl)) { 106 if (ip_route_output_key(&init_net, &rt, &fl)) {
103 IP_VS_DBG_RL("ip_route_output error, dest: " 107 IP_VS_DBG_RL("ip_route_output error, dest: "
104 "%u.%u.%u.%u\n", NIPQUAD(cp->daddr)); 108 "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
105 return NULL; 109 return NULL;
106 } 110 }
107 } 111 }
@@ -109,6 +113,70 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
109 return rt; 113 return rt;
110} 114}
111 115
116#ifdef CONFIG_IP_VS_IPV6
117static struct rt6_info *
118__ip_vs_get_out_rt_v6(struct ip_vs_conn *cp)
119{
120 struct rt6_info *rt; /* Route to the other host */
121 struct ip_vs_dest *dest = cp->dest;
122
123 if (dest) {
124 spin_lock(&dest->dst_lock);
125 rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0, 0);
126 if (!rt) {
127 struct flowi fl = {
128 .oif = 0,
129 .nl_u = {
130 .ip6_u = {
131 .daddr = dest->addr.in6,
132 .saddr = {
133 .s6_addr32 =
134 { 0, 0, 0, 0 },
135 },
136 },
137 },
138 };
139
140 rt = (struct rt6_info *)ip6_route_output(&init_net,
141 NULL, &fl);
142 if (!rt) {
143 spin_unlock(&dest->dst_lock);
144 IP_VS_DBG_RL("ip6_route_output error, "
145 "dest: " NIP6_FMT "\n",
146 NIP6(dest->addr.in6));
147 return NULL;
148 }
149 __ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
150 IP_VS_DBG(10, "new dst " NIP6_FMT ", refcnt=%d\n",
151 NIP6(dest->addr.in6),
152 atomic_read(&rt->u.dst.__refcnt));
153 }
154 spin_unlock(&dest->dst_lock);
155 } else {
156 struct flowi fl = {
157 .oif = 0,
158 .nl_u = {
159 .ip6_u = {
160 .daddr = cp->daddr.in6,
161 .saddr = {
162 .s6_addr32 = { 0, 0, 0, 0 },
163 },
164 },
165 },
166 };
167
168 rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
169 if (!rt) {
170 IP_VS_DBG_RL("ip6_route_output error, dest: "
171 NIP6_FMT "\n", NIP6(cp->daddr.in6));
172 return NULL;
173 }
174 }
175
176 return rt;
177}
178#endif
179
112 180
113/* 181/*
114 * Release dest->dst_cache before a dest is removed 182 * Release dest->dst_cache before a dest is removed
@@ -123,11 +191,11 @@ ip_vs_dst_reset(struct ip_vs_dest *dest)
123 dst_release(old_dst); 191 dst_release(old_dst);
124} 192}
125 193
126#define IP_VS_XMIT(skb, rt) \ 194#define IP_VS_XMIT(pf, skb, rt) \
127do { \ 195do { \
128 (skb)->ipvs_property = 1; \ 196 (skb)->ipvs_property = 1; \
129 skb_forward_csum(skb); \ 197 skb_forward_csum(skb); \
130 NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, (skb), NULL, \ 198 NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
131 (rt)->u.dst.dev, dst_output); \ 199 (rt)->u.dst.dev, dst_output); \
132} while (0) 200} while (0)
133 201
@@ -200,7 +268,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
200 /* Another hack: avoid icmp_send in ip_fragment */ 268 /* Another hack: avoid icmp_send in ip_fragment */
201 skb->local_df = 1; 269 skb->local_df = 1;
202 270
203 IP_VS_XMIT(skb, rt); 271 IP_VS_XMIT(PF_INET, skb, rt);
204 272
205 LeaveFunction(10); 273 LeaveFunction(10);
206 return NF_STOLEN; 274 return NF_STOLEN;
@@ -213,6 +281,70 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
213 return NF_STOLEN; 281 return NF_STOLEN;
214} 282}
215 283
284#ifdef CONFIG_IP_VS_IPV6
285int
286ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
287 struct ip_vs_protocol *pp)
288{
289 struct rt6_info *rt; /* Route to the other host */
290 struct ipv6hdr *iph = ipv6_hdr(skb);
291 int mtu;
292 struct flowi fl = {
293 .oif = 0,
294 .nl_u = {
295 .ip6_u = {
296 .daddr = iph->daddr,
297 .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
298 };
299
300 EnterFunction(10);
301
302 rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
303 if (!rt) {
304 IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, "
305 "dest: " NIP6_FMT "\n", NIP6(iph->daddr));
306 goto tx_error_icmp;
307 }
308
309 /* MTU checking */
310 mtu = dst_mtu(&rt->u.dst);
311 if (skb->len > mtu) {
312 dst_release(&rt->u.dst);
313 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
314 IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): frag needed\n");
315 goto tx_error;
316 }
317
318 /*
319 * Call ip_send_check because we are not sure it is called
320 * after ip_defrag. Is copy-on-write needed?
321 */
322 skb = skb_share_check(skb, GFP_ATOMIC);
323 if (unlikely(skb == NULL)) {
324 dst_release(&rt->u.dst);
325 return NF_STOLEN;
326 }
327
328 /* drop old route */
329 dst_release(skb->dst);
330 skb->dst = &rt->u.dst;
331
332 /* Another hack: avoid icmp_send in ip_fragment */
333 skb->local_df = 1;
334
335 IP_VS_XMIT(PF_INET6, skb, rt);
336
337 LeaveFunction(10);
338 return NF_STOLEN;
339
340 tx_error_icmp:
341 dst_link_failure(skb);
342 tx_error:
343 kfree_skb(skb);
344 LeaveFunction(10);
345 return NF_STOLEN;
346}
347#endif
216 348
217/* 349/*
218 * NAT transmitter (only for outside-to-inside nat forwarding) 350 * NAT transmitter (only for outside-to-inside nat forwarding)
@@ -264,7 +396,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
264 /* mangle the packet */ 396 /* mangle the packet */
265 if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) 397 if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
266 goto tx_error; 398 goto tx_error;
267 ip_hdr(skb)->daddr = cp->daddr; 399 ip_hdr(skb)->daddr = cp->daddr.ip;
268 ip_send_check(ip_hdr(skb)); 400 ip_send_check(ip_hdr(skb));
269 401
270 IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); 402 IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
@@ -276,7 +408,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
276 /* Another hack: avoid icmp_send in ip_fragment */ 408 /* Another hack: avoid icmp_send in ip_fragment */
277 skb->local_df = 1; 409 skb->local_df = 1;
278 410
279 IP_VS_XMIT(skb, rt); 411 IP_VS_XMIT(PF_INET, skb, rt);
280 412
281 LeaveFunction(10); 413 LeaveFunction(10);
282 return NF_STOLEN; 414 return NF_STOLEN;
@@ -292,6 +424,83 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
292 goto tx_error; 424 goto tx_error;
293} 425}
294 426
427#ifdef CONFIG_IP_VS_IPV6
428int
429ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
430 struct ip_vs_protocol *pp)
431{
432 struct rt6_info *rt; /* Route to the other host */
433 int mtu;
434
435 EnterFunction(10);
436
437 /* check if it is a connection of no-client-port */
438 if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
439 __be16 _pt, *p;
440 p = skb_header_pointer(skb, sizeof(struct ipv6hdr),
441 sizeof(_pt), &_pt);
442 if (p == NULL)
443 goto tx_error;
444 ip_vs_conn_fill_cport(cp, *p);
445 IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
446 }
447
448 rt = __ip_vs_get_out_rt_v6(cp);
449 if (!rt)
450 goto tx_error_icmp;
451
452 /* MTU checking */
453 mtu = dst_mtu(&rt->u.dst);
454 if (skb->len > mtu) {
455 dst_release(&rt->u.dst);
456 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
457 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
458 "ip_vs_nat_xmit_v6(): frag needed for");
459 goto tx_error;
460 }
461
462 /* copy-on-write the packet before mangling it */
463 if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
464 goto tx_error_put;
465
466 if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
467 goto tx_error_put;
468
469 /* drop old route */
470 dst_release(skb->dst);
471 skb->dst = &rt->u.dst;
472
473 /* mangle the packet */
474 if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
475 goto tx_error;
476 ipv6_hdr(skb)->daddr = cp->daddr.in6;
477
478 IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
479
480 /* FIXME: when application helper enlarges the packet and the length
481 is larger than the MTU of outgoing device, there will be still
482 MTU problem. */
483
484 /* Another hack: avoid icmp_send in ip_fragment */
485 skb->local_df = 1;
486
487 IP_VS_XMIT(PF_INET6, skb, rt);
488
489 LeaveFunction(10);
490 return NF_STOLEN;
491
492tx_error_icmp:
493 dst_link_failure(skb);
494tx_error:
495 LeaveFunction(10);
496 kfree_skb(skb);
497 return NF_STOLEN;
498tx_error_put:
499 dst_release(&rt->u.dst);
500 goto tx_error;
501}
502#endif
503
295 504
296/* 505/*
297 * IP Tunneling transmitter 506 * IP Tunneling transmitter
@@ -423,6 +632,112 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
423 return NF_STOLEN; 632 return NF_STOLEN;
424} 633}
425 634
635#ifdef CONFIG_IP_VS_IPV6
636int
637ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
638 struct ip_vs_protocol *pp)
639{
640 struct rt6_info *rt; /* Route to the other host */
641 struct net_device *tdev; /* Device to other host */
642 struct ipv6hdr *old_iph = ipv6_hdr(skb);
643 sk_buff_data_t old_transport_header = skb->transport_header;
644 struct ipv6hdr *iph; /* Our new IP header */
645 unsigned int max_headroom; /* The extra header space needed */
646 int mtu;
647
648 EnterFunction(10);
649
650 if (skb->protocol != htons(ETH_P_IPV6)) {
651 IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): protocol error, "
652 "ETH_P_IPV6: %d, skb protocol: %d\n",
653 htons(ETH_P_IPV6), skb->protocol);
654 goto tx_error;
655 }
656
657 rt = __ip_vs_get_out_rt_v6(cp);
658 if (!rt)
659 goto tx_error_icmp;
660
661 tdev = rt->u.dst.dev;
662
663 mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
664 /* TODO IPv6: do we need this check in IPv6? */
665 if (mtu < 1280) {
666 dst_release(&rt->u.dst);
667 IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n");
668 goto tx_error;
669 }
670 if (skb->dst)
671 skb->dst->ops->update_pmtu(skb->dst, mtu);
672
673 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
674 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
675 dst_release(&rt->u.dst);
676 IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): frag needed\n");
677 goto tx_error;
678 }
679
680 /*
681 * Okay, now see if we can stuff it in the buffer as-is.
682 */
683 max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
684
685 if (skb_headroom(skb) < max_headroom
686 || skb_cloned(skb) || skb_shared(skb)) {
687 struct sk_buff *new_skb =
688 skb_realloc_headroom(skb, max_headroom);
689 if (!new_skb) {
690 dst_release(&rt->u.dst);
691 kfree_skb(skb);
692 IP_VS_ERR_RL("ip_vs_tunnel_xmit_v6(): no memory\n");
693 return NF_STOLEN;
694 }
695 kfree_skb(skb);
696 skb = new_skb;
697 old_iph = ipv6_hdr(skb);
698 }
699
700 skb->transport_header = old_transport_header;
701
702 skb_push(skb, sizeof(struct ipv6hdr));
703 skb_reset_network_header(skb);
704 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
705
706 /* drop old route */
707 dst_release(skb->dst);
708 skb->dst = &rt->u.dst;
709
710 /*
711 * Push down and install the IPIP header.
712 */
713 iph = ipv6_hdr(skb);
714 iph->version = 6;
715 iph->nexthdr = IPPROTO_IPV6;
716 iph->payload_len = old_iph->payload_len + sizeof(old_iph);
717 iph->priority = old_iph->priority;
718 memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
719 iph->daddr = rt->rt6i_dst.addr;
720 iph->saddr = cp->vaddr.in6; /* rt->rt6i_src.addr; */
721 iph->hop_limit = old_iph->hop_limit;
722
723 /* Another hack: avoid icmp_send in ip_fragment */
724 skb->local_df = 1;
725
726 ip6_local_out(skb);
727
728 LeaveFunction(10);
729
730 return NF_STOLEN;
731
732tx_error_icmp:
733 dst_link_failure(skb);
734tx_error:
735 kfree_skb(skb);
736 LeaveFunction(10);
737 return NF_STOLEN;
738}
739#endif
740
426 741
427/* 742/*
428 * Direct Routing transmitter 743 * Direct Routing transmitter
@@ -467,7 +782,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
467 /* Another hack: avoid icmp_send in ip_fragment */ 782 /* Another hack: avoid icmp_send in ip_fragment */
468 skb->local_df = 1; 783 skb->local_df = 1;
469 784
470 IP_VS_XMIT(skb, rt); 785 IP_VS_XMIT(PF_INET, skb, rt);
471 786
472 LeaveFunction(10); 787 LeaveFunction(10);
473 return NF_STOLEN; 788 return NF_STOLEN;
@@ -480,6 +795,60 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
480 return NF_STOLEN; 795 return NF_STOLEN;
481} 796}
482 797
798#ifdef CONFIG_IP_VS_IPV6
799int
800ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
801 struct ip_vs_protocol *pp)
802{
803 struct rt6_info *rt; /* Route to the other host */
804 int mtu;
805
806 EnterFunction(10);
807
808 rt = __ip_vs_get_out_rt_v6(cp);
809 if (!rt)
810 goto tx_error_icmp;
811
812 /* MTU checking */
813 mtu = dst_mtu(&rt->u.dst);
814 if (skb->len > mtu) {
815 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
816 dst_release(&rt->u.dst);
817 IP_VS_DBG_RL("ip_vs_dr_xmit_v6(): frag needed\n");
818 goto tx_error;
819 }
820
821 /*
822 * Call ip_send_check because we are not sure it is called
823 * after ip_defrag. Is copy-on-write needed?
824 */
825 skb = skb_share_check(skb, GFP_ATOMIC);
826 if (unlikely(skb == NULL)) {
827 dst_release(&rt->u.dst);
828 return NF_STOLEN;
829 }
830
831 /* drop old route */
832 dst_release(skb->dst);
833 skb->dst = &rt->u.dst;
834
835 /* Another hack: avoid icmp_send in ip_fragment */
836 skb->local_df = 1;
837
838 IP_VS_XMIT(PF_INET6, skb, rt);
839
840 LeaveFunction(10);
841 return NF_STOLEN;
842
843tx_error_icmp:
844 dst_link_failure(skb);
845tx_error:
846 kfree_skb(skb);
847 LeaveFunction(10);
848 return NF_STOLEN;
849}
850#endif
851
483 852
484/* 853/*
485 * ICMP packet transmitter 854 * ICMP packet transmitter
@@ -540,7 +909,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
540 /* Another hack: avoid icmp_send in ip_fragment */ 909 /* Another hack: avoid icmp_send in ip_fragment */
541 skb->local_df = 1; 910 skb->local_df = 1;
542 911
543 IP_VS_XMIT(skb, rt); 912 IP_VS_XMIT(PF_INET, skb, rt);
544 913
545 rc = NF_STOLEN; 914 rc = NF_STOLEN;
546 goto out; 915 goto out;
@@ -557,3 +926,79 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
557 ip_rt_put(rt); 926 ip_rt_put(rt);
558 goto tx_error; 927 goto tx_error;
559} 928}
929
930#ifdef CONFIG_IP_VS_IPV6
931int
932ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
933 struct ip_vs_protocol *pp, int offset)
934{
935 struct rt6_info *rt; /* Route to the other host */
936 int mtu;
937 int rc;
938
939 EnterFunction(10);
940
941 /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
942 forwarded directly here, because there is no need to
943 translate address/port back */
944 if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
945 if (cp->packet_xmit)
946 rc = cp->packet_xmit(skb, cp, pp);
947 else
948 rc = NF_ACCEPT;
949 /* do not touch skb anymore */
950 atomic_inc(&cp->in_pkts);
951 goto out;
952 }
953
954 /*
955 * mangle and send the packet here (only for VS/NAT)
956 */
957
958 rt = __ip_vs_get_out_rt_v6(cp);
959 if (!rt)
960 goto tx_error_icmp;
961
962 /* MTU checking */
963 mtu = dst_mtu(&rt->u.dst);
964 if (skb->len > mtu) {
965 dst_release(&rt->u.dst);
966 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
967 IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
968 goto tx_error;
969 }
970
971 /* copy-on-write the packet before mangling it */
972 if (!skb_make_writable(skb, offset))
973 goto tx_error_put;
974
975 if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
976 goto tx_error_put;
977
978 /* drop the old route when skb is not shared */
979 dst_release(skb->dst);
980 skb->dst = &rt->u.dst;
981
982 ip_vs_nat_icmp_v6(skb, pp, cp, 0);
983
984 /* Another hack: avoid icmp_send in ip_fragment */
985 skb->local_df = 1;
986
987 IP_VS_XMIT(PF_INET6, skb, rt);
988
989 rc = NF_STOLEN;
990 goto out;
991
992tx_error_icmp:
993 dst_link_failure(skb);
994tx_error:
995 dev_kfree_skb(skb);
996 rc = NF_STOLEN;
997out:
998 LeaveFunction(10);
999 return rc;
1000tx_error_put:
1001 dst_release(&rt->u.dst);
1002 goto tx_error;
1003}
1004#endif