netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS
@ 2008-09-01 12:55 Julius Volz
  2008-09-01 12:55 ` [PATCHv2 RFC 01/25] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
                   ` (25 more replies)
  0 siblings, 26 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:55 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam

I now managed to rework the IPVS IPv6 patches in a way that the kernel
builds after each patch in the series. Sometimes, this adds some
ugliness in the form of temporary constructs which are introduced in one
patch and deleted in the next ones. I've also integrated other small bug
fixes and cleanups from comments on the mailing lists.

Note: these patches are not based on net-2.6 anymore, but on lvs-2.6:

git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-2.6.git

- Full kernel patch in one file:
  http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6_v2.patch

While not all IPv6 features are working or tested, existing IPv4 features
should still work as before. However, to use any of the new features, you
will need a new ipvsadm with support for genetlink and IPv6:

  http://sixpak.org/vince/google/ipvsadm/
  (by Vince Busam)

To enable IPv6 support in IPVS, set CONFIG_IP_VS_IPV6=y.

Short overview:

What works with IPv6:
- forwarding mechanisms: NAT, DR, maybe Tunnel (not fully tested yet)
- protocols: TCP, UDP, ESP, AH (last two not tested)
- manipulation and inspection of both IPv4 and IPv6 entries with ipvsadm
- 6 out of 10 schedulers

What is not supported with IPv6:
- handling fragmentation or other extension headers
- FTP application helper (can be loaded, but only operates on v4)
- sync daemon (can be started, but only operates on v4)
- probably some incorrect handling of ICMPv6 or other corner cases

Since fragmentation and extension headers should not occur very often,
things should "mostly" work. I tested HTTP and DNS over NAT and DR
with various supported schedulers without encountering any problems.
But we didn't test any exotic situations. Also, there are some TODOs
in the code for things that haven't been tested or implemented yet.

Thanks for any comments!

Julius

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 01/25] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
@ 2008-09-01 12:55 ` Julius Volz
  2008-09-01 12:55 ` [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:55 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add boolean config option CONFIG_IP_VS_IPV6 for enabling experimental IPv6
support in IPVS. Only visible if IPv6 support is set to 'y' or both IPv6
and IPVS are modules.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
index 2e48a7e..794cecb 100644
--- a/net/ipv4/ipvs/Kconfig
+++ b/net/ipv4/ipvs/Kconfig
@@ -24,6 +24,14 @@ menuconfig IP_VS
 
 if IP_VS
 
+config	IP_VS_IPV6
+	bool "IPv6 support for IPVS (DANGEROUS)"
+	depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6)
+	---help---
+	  Add IPv6 support to IPVS. This is incomplete and might be dangerous.
+
+	  Say N if unsure.
+
 config	IP_VS_DEBUG
 	bool "IP virtual server debugging"
 	---help---
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
  2008-09-01 12:55 ` [PATCHv2 RFC 01/25] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
@ 2008-09-01 12:55 ` Julius Volz
  2008-09-02  5:23   ` Simon Horman
  2008-09-02  6:08   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 03/25] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
                   ` (23 subsequent siblings)
  25 siblings, 2 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:55 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Introduce new 'af' fields into IPVS data structures for specifying an
entry's address family. Convert IP addresses to be of type union
nf_inet_addr.

Signed-off-by: Julius Volz <juliusv@google.com>

 19 files changed, 118 insertions(+), 112 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index a25ad24..01cabd6 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -21,6 +21,9 @@
 #include <linux/timer.h>
 
 #include <net/checksum.h>
+#include <linux/netfilter.h>		/* for union nf_inet_addr */
+#include <linux/ipv6.h>			/* for struct ipv6hdr */
+#include <net/ipv6.h>			/* for ipv6_addr_copy */
 
 #ifdef CONFIG_IP_VS_DEBUG
 #include <linux/net.h>
@@ -259,9 +262,10 @@ struct ip_vs_conn {
 	struct list_head        c_list;         /* hashed list heads */
 
 	/* Protocol, addresses and port numbers */
-	__be32                   caddr;          /* client address */
-	__be32                   vaddr;          /* virtual address */
-	__be32                   daddr;          /* destination address */
+	u_int16_t               af;		/* address family */
+	union nf_inet_addr       caddr;          /* client address */
+	union nf_inet_addr       vaddr;          /* virtual address */
+	union nf_inet_addr       daddr;          /* destination address */
 	__be16                   cport;
 	__be16                   vport;
 	__be16                   dport;
@@ -314,8 +318,9 @@ struct ip_vs_service {
 	atomic_t		refcnt;   /* reference counter */
 	atomic_t		usecnt;   /* use counter */
 
+	u_int16_t               af;       /* address family */
 	__u16			protocol; /* which protocol (TCP/UDP) */
-	__be32			addr;	  /* IP address for virtual service */
+	union nf_inet_addr	addr;	  /* IP address for virtual service */
 	__be16			port;	  /* port number for the service */
 	__u32                   fwmark;   /* firewall mark of the service */
 	unsigned		flags;	  /* service status flags */
@@ -342,7 +347,8 @@ struct ip_vs_dest {
 	struct list_head	n_list;   /* for the dests in the service */
 	struct list_head	d_list;   /* for table with all the dests */
 
-	__be32			addr;		/* IP address of the server */
+	u_int16_t		af;		/* address family */
+	union nf_inet_addr	addr;		/* IP address of the server */
 	__be16			port;		/* port number of the server */
 	volatile unsigned	flags;		/* dest status flags */
 	atomic_t		conn_flags;	/* flags to copy to conn */
@@ -366,7 +372,7 @@ struct ip_vs_dest {
 	/* for virtual service */
 	struct ip_vs_service	*svc;		/* service it belongs to */
 	__u16			protocol;	/* which protocol (TCP/UDP) */
-	__be32			vaddr;		/* virtual IP address */
+	union nf_inet_addr	vaddr;		/* virtual IP address */
 	__be16			vport;		/* virtual port number */
 	__u32			vfwmark;	/* firewall mark of service */
 };
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 44a6872..c7f0c2d 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -131,7 +131,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
 	int ret;
 
 	/* Hash by protocol, client address and port */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
 
 	ct_write_lock(hash);
 
@@ -162,7 +162,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
 	int ret;
 
 	/* unhash it and decrease its reference counter */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
 
 	ct_write_lock(hash);
 
@@ -197,8 +197,8 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
+		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
+		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
 		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
 		    protocol==cp->protocol) {
 			/* HIT */
@@ -243,8 +243,8 @@ struct ip_vs_conn *ip_vs_ct_in_get
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
+		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
+		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
 		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
 		    protocol==cp->protocol) {
 			/* HIT */
@@ -286,8 +286,8 @@ struct ip_vs_conn *ip_vs_conn_out_get
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (d_addr == cp->caddr && d_port == cp->cport &&
-		    s_port == cp->dport && s_addr == cp->daddr &&
+		if (d_addr == cp->caddr.ip && d_port == cp->cport &&
+		    s_port == cp->dport && s_addr == cp->daddr.ip &&
 		    protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
@@ -406,9 +406,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
 		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
 		  "dest->refcnt:%d\n",
 		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
 		  ip_vs_fwd_tag(cp), cp->state,
 		  cp->flags, atomic_read(&cp->refcnt),
 		  atomic_read(&dest->refcnt));
@@ -444,8 +444,8 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
 	struct ip_vs_dest *dest;
 
 	if ((cp) && (!cp->dest)) {
-		dest = ip_vs_find_dest(cp->daddr, cp->dport,
-				       cp->vaddr, cp->vport, cp->protocol);
+		dest = ip_vs_find_dest(cp->daddr.ip, cp->dport,
+				       cp->vaddr.ip, cp->vport, cp->protocol);
 		ip_vs_bind_dest(cp, dest);
 		return dest;
 	} else
@@ -468,9 +468,9 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
 		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
 		  "dest->refcnt:%d\n",
 		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
 		  ip_vs_fwd_tag(cp), cp->state,
 		  cp->flags, atomic_read(&cp->refcnt),
 		  atomic_read(&dest->refcnt));
@@ -530,9 +530,9 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
 			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
 			  "-> d:%u.%u.%u.%u:%d\n",
 			  ip_vs_proto_name(ct->protocol),
-			  NIPQUAD(ct->caddr), ntohs(ct->cport),
-			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
-			  NIPQUAD(ct->daddr), ntohs(ct->dport));
+			  NIPQUAD(ct->caddr.ip), ntohs(ct->cport),
+			  NIPQUAD(ct->vaddr.ip), ntohs(ct->vport),
+			  NIPQUAD(ct->daddr.ip), ntohs(ct->dport));
 
 		/*
 		 * Invalidate the connection template
@@ -641,11 +641,11 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
 	INIT_LIST_HEAD(&cp->c_list);
 	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
 	cp->protocol	   = proto;
-	cp->caddr	   = caddr;
+	cp->caddr.ip	   = caddr;
 	cp->cport	   = cport;
-	cp->vaddr	   = vaddr;
+	cp->vaddr.ip	   = vaddr;
 	cp->vport	   = vport;
-	cp->daddr          = daddr;
+	cp->daddr.ip	   = daddr;
 	cp->dport          = dport;
 	cp->flags	   = flags;
 	spin_lock_init(&cp->lock);
@@ -763,9 +763,9 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
 		seq_printf(seq,
 			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
-				ntohl(cp->caddr), ntohs(cp->cport),
-				ntohl(cp->vaddr), ntohs(cp->vport),
-				ntohl(cp->daddr), ntohs(cp->dport),
+				ntohl(cp->caddr.ip), ntohs(cp->cport),
+				ntohl(cp->vaddr.ip), ntohs(cp->vport),
+				ntohl(cp->daddr.ip), ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
 				(cp->timer.expires-jiffies)/HZ);
 	}
@@ -812,9 +812,9 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
 		seq_printf(seq,
 			"%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
-				ntohl(cp->caddr), ntohs(cp->cport),
-				ntohl(cp->vaddr), ntohs(cp->vport),
-				ntohl(cp->daddr), ntohs(cp->dport),
+				ntohl(cp->caddr.ip), ntohs(cp->cport),
+				ntohl(cp->vaddr.ip), ntohs(cp->vport),
+				ntohl(cp->daddr.ip), ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
 				ip_vs_origin_name(cp->flags),
 				(cp->timer.expires-jiffies)/HZ);
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 9fbf0a6..a07e5b7 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -232,14 +232,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 						    snet, 0,
 						    iph->daddr,
 						    ports[1],
-						    dest->addr, dest->port,
+						    dest->addr.ip, dest->port,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			else
 				ct = ip_vs_conn_new(iph->protocol,
 						    snet, 0,
 						    iph->daddr, 0,
-						    dest->addr, 0,
+						    dest->addr.ip, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -286,14 +286,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 				ct = ip_vs_conn_new(IPPROTO_IP,
 						    snet, 0,
 						    htonl(svc->fwmark), 0,
-						    dest->addr, 0,
+						    dest->addr.ip, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			else
 				ct = ip_vs_conn_new(iph->protocol,
 						    snet, 0,
 						    iph->daddr, 0,
-						    dest->addr, 0,
+						    dest->addr.ip, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -313,7 +313,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	cp = ip_vs_conn_new(iph->protocol,
 			    iph->saddr, ports[0],
 			    iph->daddr, ports[1],
-			    dest->addr, dport,
+			    dest->addr.ip, dport,
 			    0,
 			    dest);
 	if (cp == NULL) {
@@ -380,7 +380,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	cp = ip_vs_conn_new(iph->protocol,
 			    iph->saddr, pptr[0],
 			    iph->daddr, pptr[1],
-			    dest->addr, dest->port?dest->port:pptr[1],
+			    dest->addr.ip, dest->port?dest->port:pptr[1],
 			    0,
 			    dest);
 	if (cp == NULL)
@@ -389,9 +389,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
 		  "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
 		  ip_vs_fwd_tag(cp),
-		  NIPQUAD(cp->caddr), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
 		  cp->flags, atomic_read(&cp->refcnt));
 
 	ip_vs_conn_stats(cp, svc);
@@ -526,14 +526,14 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
 	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
 
 	if (inout) {
-		iph->saddr = cp->vaddr;
+		iph->saddr = cp->vaddr.ip;
 		ip_send_check(iph);
-		ciph->daddr = cp->vaddr;
+		ciph->daddr = cp->vaddr.ip;
 		ip_send_check(ciph);
 	} else {
-		iph->daddr = cp->daddr;
+		iph->daddr = cp->daddr.ip;
 		ip_send_check(iph);
-		ciph->saddr = cp->daddr;
+		ciph->saddr = cp->daddr.ip;
 		ip_send_check(ciph);
 	}
 
@@ -762,7 +762,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 	/* mangle the packet */
 	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
 		goto drop;
-	ip_hdr(skb)->saddr = cp->vaddr;
+	ip_hdr(skb)->saddr = cp->vaddr.ip;
 	ip_send_check(ip_hdr(skb));
 
 	/* For policy routing, packets originating from this
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index ede101e..47644f3 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -317,7 +317,7 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
 		/*
 		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
 		 */
-		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port);
+		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr.ip, svc->port);
 		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
 	} else {
 		/*
@@ -373,7 +373,7 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
 	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
 
 	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
-		if ((svc->addr == vaddr)
+		if ((svc->addr.ip == vaddr)
 		    && (svc->port == vport)
 		    && (svc->protocol == protocol)) {
 			/* HIT */
@@ -503,7 +503,7 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
 	 *	Hash by proto,addr,port,
 	 *	which are the parameters of the real service.
 	 */
-	hash = ip_vs_rs_hashkey(dest->addr, dest->port);
+	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
 	list_add(&dest->d_list, &ip_vs_rtable[hash]);
 
 	return 1;
@@ -543,7 +543,7 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
 
 	read_lock(&__ip_vs_rs_lock);
 	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
-		if ((dest->addr == daddr)
+		if ((dest->addr.ip == daddr)
 		    && (dest->port == dport)
 		    && ((dest->protocol == protocol) ||
 			dest->vfwmark)) {
@@ -569,7 +569,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 	 * Find the destination for the given service
 	 */
 	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if ((dest->addr == daddr) && (dest->port == dport)) {
+		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
 			/* HIT */
 			return dest;
 		}
@@ -626,14 +626,14 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
 			  "dest->refcnt=%d\n",
 			  dest->vfwmark,
-			  NIPQUAD(dest->addr), ntohs(dest->port),
+			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
 			  atomic_read(&dest->refcnt));
-		if (dest->addr == daddr &&
+		if (dest->addr.ip == daddr &&
 		    dest->port == dport &&
 		    dest->vfwmark == svc->fwmark &&
 		    dest->protocol == svc->protocol &&
 		    (svc->fwmark ||
-		     (dest->vaddr == svc->addr &&
+		     (dest->vaddr.ip == svc->addr.ip &&
 		      dest->vport == svc->port))) {
 			/* HIT */
 			return dest;
@@ -646,7 +646,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
 				  "from trash\n",
 				  dest->vfwmark,
-				  NIPQUAD(dest->addr), ntohs(dest->port));
+				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
 			list_del(&dest->n_list);
 			ip_vs_dst_reset(dest);
 			__ip_vs_unbind_svc(dest);
@@ -779,10 +779,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
 	}
 
 	dest->protocol = svc->protocol;
-	dest->vaddr = svc->addr;
+	dest->vaddr.ip = svc->addr.ip;
 	dest->vport = svc->port;
 	dest->vfwmark = svc->fwmark;
-	dest->addr = udest->addr;
+	dest->addr.ip = udest->addr;
 	dest->port = udest->port;
 
 	atomic_set(&dest->activeconns, 0);
@@ -847,7 +847,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 			  NIPQUAD(daddr), ntohs(dport),
 			  atomic_read(&dest->refcnt),
 			  dest->vfwmark,
-			  NIPQUAD(dest->vaddr),
+			  NIPQUAD(dest->vaddr.ip),
 			  ntohs(dest->vport));
 		__ip_vs_update_dest(svc, dest, udest);
 
@@ -993,7 +993,7 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
 	} else {
 		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
 			  "dest->refcnt=%d\n",
-			  NIPQUAD(dest->addr), ntohs(dest->port),
+			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
 			  atomic_read(&dest->refcnt));
 		list_add(&dest->n_list, &ip_vs_dest_trash);
 		atomic_inc(&dest->refcnt);
@@ -1101,7 +1101,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
 	atomic_set(&svc->refcnt, 0);
 
 	svc->protocol = u->protocol;
-	svc->addr = u->addr;
+	svc->addr.ip = u->addr;
 	svc->port = u->port;
 	svc->fwmark = u->fwmark;
 	svc->flags = u->flags;
@@ -1751,7 +1751,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
 		if (iter->table == ip_vs_svc_table)
 			seq_printf(seq, "%s  %08X:%04X %s ",
 				   ip_vs_proto_name(svc->protocol),
-				   ntohl(svc->addr),
+				   ntohl(svc->addr.ip),
 				   ntohs(svc->port),
 				   svc->scheduler->name);
 		else
@@ -1768,7 +1768,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
 		list_for_each_entry(dest, &svc->destinations, n_list) {
 			seq_printf(seq,
 				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
-				   ntohl(dest->addr), ntohs(dest->port),
+				   ntohl(dest->addr.ip), ntohs(dest->port),
 				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
 				   atomic_read(&dest->weight),
 				   atomic_read(&dest->activeconns),
@@ -2040,7 +2040,7 @@ static void
 ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
 {
 	dst->protocol = src->protocol;
-	dst->addr = src->addr;
+	dst->addr = src->addr.ip;
 	dst->port = src->port;
 	dst->fwmark = src->fwmark;
 	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
@@ -2114,7 +2114,7 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
 			if (count >= get->num_dests)
 				break;
 
-			entry.addr = dest->addr;
+			entry.addr = dest->addr.ip;
 			entry.port = dest->port;
 			entry.conn_flags = atomic_read(&dest->conn_flags);
 			entry.weight = atomic_read(&dest->weight);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index fa66824..9f9d795 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)
 	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
 		  "--> server %u.%u.%u.%u:%d\n",
 		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr),
+		  NIPQUAD(dest->addr.ip),
 		  ntohs(dest->port));
 
 	return dest;
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index c1c758e..bfe5d70 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -172,17 +172,17 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 
 		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
 			  "%u.%u.%u.%u:%d detected\n",
-			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0);
+			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr.ip), 0);
 
 		/*
 		 * Now update or create an connection entry for it
 		 */
 		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
-					  cp->caddr, 0);
+					  cp->caddr.ip, 0);
 		if (!n_cp) {
 			n_cp = ip_vs_conn_new(IPPROTO_TCP,
-					      cp->caddr, 0,
-					      cp->vaddr, port,
+					      cp->caddr.ip, 0,
+					      cp->vaddr.ip, port,
 					      from, port,
 					      IP_VS_CONN_F_NO_CPORT,
 					      cp->dest);
@@ -196,7 +196,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 		/*
 		 * Replace the old passive address with the new one
 		 */
-		from = n_cp->vaddr;
+		from = n_cp->vaddr.ip;
 		port = n_cp->vport;
 		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
 			(ntohs(port)>>8)&255, ntohs(port)&255);
@@ -306,16 +306,16 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	 */
 	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
 		  ip_vs_proto_name(iph->protocol),
-		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr), 0);
+		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
 
 	n_cp = ip_vs_conn_in_get(iph->protocol,
 				 to, port,
-				 cp->vaddr, htons(ntohs(cp->vport)-1));
+				 cp->vaddr.ip, htons(ntohs(cp->vport)-1));
 	if (!n_cp) {
 		n_cp = ip_vs_conn_new(IPPROTO_TCP,
 				      to, port,
-				      cp->vaddr, htons(ntohs(cp->vport)-1),
-				      cp->daddr, htons(ntohs(cp->dport)-1),
+				      cp->vaddr.ip, htons(ntohs(cp->vport)-1),
+				      cp->daddr.ip, htons(ntohs(cp->dport)-1),
 				      0,
 				      cp->dest);
 		if (!n_cp)
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index d2a43aa..69309ed 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)
 
 	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  atomic_read(&least->weight), loh);
@@ -506,7 +506,7 @@ out:
 	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
 		  "--> server %u.%u.%u.%u:%d\n",
 		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr),
+		  NIPQUAD(dest->addr.ip),
 		  ntohs(dest->port));
 
 	return dest;
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 375a1ff..51c746e 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)
 
 	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  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)
 
 	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(most->addr), ntohs(most->port),
+		  NIPQUAD(most->addr.ip), ntohs(most->port),
 		  atomic_read(&most->activeconns),
 		  atomic_read(&most->refcnt),
 		  atomic_read(&most->weight), moh);
@@ -598,7 +598,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
 
 	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  atomic_read(&least->weight), loh);
@@ -706,7 +706,7 @@ out:
 	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
 		  "--> server %u.%u.%u.%u:%d\n",
 		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr),
+		  NIPQUAD(dest->addr.ip),
 		  ntohs(dest->port));
 
 	return dest;
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index 2c3de1b..551d293 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -68,7 +68,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 
 	if (least)
 	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->inactconns));
 
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index 5330d5a..aa0e32a 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -101,7 +101,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
   out:
 	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  atomic_read(&least->weight), loh);
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index d0ea467..15860e1 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -147,7 +147,7 @@ tcp_snat_handler(struct sk_buff *skb,
 	/* Adjust TCP checksums */
 	if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
+		tcp_fast_csum_update(tcph, cp->daddr.ip, cp->vaddr.ip,
 				     cp->dport, cp->vport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -155,7 +155,7 @@ tcp_snat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		tcph->check = 0;
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
+		tcph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
 						skb->len - tcphoff,
 						cp->protocol, skb->csum);
 		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
@@ -198,7 +198,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
+		tcp_fast_csum_update(tcph, cp->vaddr.ip, cp->daddr.ip,
 				     cp->vport, cp->dport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -206,7 +206,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		tcph->check = 0;
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
+		tcph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
 						skb->len - tcphoff,
 						cp->protocol, skb->csum);
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -427,8 +427,8 @@ set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
 			  th->fin? 'F' : '.',
 			  th->ack? 'A' : '.',
 			  th->rst? 'R' : '.',
-			  NIPQUAD(cp->daddr), ntohs(cp->dport),
-			  NIPQUAD(cp->caddr), ntohs(cp->cport),
+			  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
+			  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
 			  tcp_state_name(cp->state),
 			  tcp_state_name(new_state),
 			  atomic_read(&cp->refcnt));
@@ -549,8 +549,8 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
 			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
 				  "%u.%u.%u.%u:%u to app %s on port %u\n",
 				  __func__,
-				  NIPQUAD(cp->caddr), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
+				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
+				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
 				  inc->name, ntohs(inc->port));
 			cp->app = inc;
 			if (inc->init_conn)
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index c6be5d5..8dfad5d 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -158,7 +158,7 @@ udp_snat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
+		udp_fast_csum_update(udph, cp->daddr.ip, cp->vaddr.ip,
 				     cp->dport, cp->vport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -166,7 +166,7 @@ udp_snat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		udph->check = 0;
 		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
+		udph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
 						skb->len - udphoff,
 						cp->protocol, skb->csum);
 		if (udph->check == 0)
@@ -211,7 +211,7 @@ udp_dnat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
+		udp_fast_csum_update(udph, cp->vaddr.ip, cp->daddr.ip,
 				     cp->vport, cp->dport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -219,7 +219,7 @@ udp_dnat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		udph->check = 0;
 		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
+		udph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
 						skb->len - udphoff,
 						cp->protocol, skb->csum);
 		if (udph->check == 0)
@@ -343,8 +343,8 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
 			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
 				  "%u.%u.%u.%u:%u to app %s on port %u\n",
 				  __func__,
-				  NIPQUAD(cp->caddr), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
+				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
+				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
 				  inc->name, ntohs(inc->port));
 			cp->app = inc;
 			if (inc->init_conn)
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index f749291..27f0b62 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -76,7 +76,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	write_unlock(&svc->sched_lock);
 	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
 		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr), ntohs(dest->port),
+		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
 		  atomic_read(&dest->activeconns),
 		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
 
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 53f73be..38b574b 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -103,7 +103,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 
 	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  atomic_read(&least->weight), loh);
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 7b979e2..c9e54e2 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)
 	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
 		  "--> server %u.%u.%u.%u:%d\n",
 		  NIPQUAD(iph->saddr),
-		  NIPQUAD(dest->addr),
+		  NIPQUAD(dest->addr.ip),
 		  ntohs(dest->port));
 
 	return dest;
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index a652da2..2cf47b2 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)
 	s->cport = cp->cport;
 	s->vport = cp->vport;
 	s->dport = cp->dport;
-	s->caddr = cp->caddr;
-	s->vaddr = cp->vaddr;
-	s->daddr = cp->daddr;
+	s->caddr = cp->caddr.ip;
+	s->vaddr = cp->vaddr.ip;
+	s->daddr = cp->daddr.ip;
 	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
 	s->state = htons(cp->state);
 	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index df7ad8d..09fd993 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -91,7 +91,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 
 	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
 		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr), ntohs(least->port),
+		  NIPQUAD(least->addr.ip), ntohs(least->port),
 		  atomic_read(&least->activeconns),
 		  atomic_read(&least->refcnt),
 		  atomic_read(&least->weight), loh);
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 0d86a79..19c49b2 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -197,7 +197,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 
 	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
 		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr), ntohs(dest->port),
+		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
 		  atomic_read(&dest->activeconns),
 		  atomic_read(&dest->refcnt),
 		  atomic_read(&dest->weight));
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 9892d4a..88199c9 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -71,7 +71,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
 				.oif = 0,
 				.nl_u = {
 					.ip4_u = {
-						.daddr = dest->addr,
+						.daddr = dest->addr.ip,
 						.saddr = 0,
 						.tos = rtos, } },
 			};
@@ -80,12 +80,12 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
 				spin_unlock(&dest->dst_lock);
 				IP_VS_DBG_RL("ip_route_output error, "
 					     "dest: %u.%u.%u.%u\n",
-					     NIPQUAD(dest->addr));
+					     NIPQUAD(dest->addr.ip));
 				return NULL;
 			}
 			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
 			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
-				  NIPQUAD(dest->addr),
+				  NIPQUAD(dest->addr.ip),
 				  atomic_read(&rt->u.dst.__refcnt), rtos);
 		}
 		spin_unlock(&dest->dst_lock);
@@ -94,14 +94,14 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
 			.oif = 0,
 			.nl_u = {
 				.ip4_u = {
-					.daddr = cp->daddr,
+					.daddr = cp->daddr.ip,
 					.saddr = 0,
 					.tos = rtos, } },
 		};
 
 		if (ip_route_output_key(&init_net, &rt, &fl)) {
 			IP_VS_DBG_RL("ip_route_output error, dest: "
-				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr));
+				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
 			return NULL;
 		}
 	}
@@ -264,7 +264,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	/* mangle the packet */
 	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
 		goto tx_error;
-	ip_hdr(skb)->daddr = cp->daddr;
+	ip_hdr(skb)->daddr = cp->daddr.ip;
 	ip_send_check(ip_hdr(skb));
 
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 03/25] IPVS: Add general v4/v6 helper functions / data structures
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
  2008-09-01 12:55 ` [PATCHv2 RFC 01/25] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
  2008-09-01 12:55 ` [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 04/25] IPVS: Add debug macros for v4 and v6 address output Julius Volz
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add a struct ip_vs_iphdr for easier handling of common v4 and v6 header
fields in the same code path. ip_vs_fill_iphdr() helps to fill this struct
from an IPv4 or IPv6 header. Add further helper functions for copying and
comparing addresses.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 01cabd6..6d9a360 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -25,6 +25,55 @@
 #include <linux/ipv6.h>			/* for struct ipv6hdr */
 #include <net/ipv6.h>			/* for ipv6_addr_copy */
 
+struct ip_vs_iphdr {
+	int len;
+	__u8 protocol;
+	union nf_inet_addr saddr;
+	union nf_inet_addr daddr;
+};
+
+static inline void
+ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		const struct ipv6hdr *iph = nh;
+		iphdr->len = sizeof(struct ipv6hdr);
+		iphdr->protocol = iph->nexthdr;
+		ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr);
+		ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr);
+	} else
+#endif
+	{
+		const struct iphdr *iph = nh;
+		iphdr->len = iph->ihl * 4;
+		iphdr->protocol = iph->protocol;
+		iphdr->saddr.ip = iph->saddr;
+		iphdr->daddr.ip = iph->daddr;
+	}
+}
+
+static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
+				   const union nf_inet_addr *src)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ipv6_addr_copy(&dst->in6, &src->in6);
+	else
+#endif
+	dst->ip = src->ip;
+}
+
+static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
+				   const union nf_inet_addr *b)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		return ipv6_addr_equal(&a->in6, &b->in6);
+#endif
+	return a->ip == b->ip;
+}
+
 #ifdef CONFIG_IP_VS_DEBUG
 #include <linux/net.h>
 
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 04/25] IPVS: Add debug macros for v4 and v6 address output
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (2 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 03/25] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs Julius Volz
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add some debugging macros that allow conditional output of either v4 or v6
addresses, depending on an 'af' parameter. This is done by creating a
temporary string buffer in an outer debug macro and writing addresses'
string representations into it from another macro which can only be used
when inside the outer one.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 6d9a360..45a7458 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -78,6 +78,46 @@ static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
 #include <linux/net.h>
 
 extern int ip_vs_get_debug_level(void);
+
+static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
+					 const union nf_inet_addr *addr,
+					 int *idx)
+{
+	int len;
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
+			       NIP6(addr->in6)) + 1;
+	else
+#endif
+		len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
+			       NIPQUAD(addr->ip)) + 1;
+
+	*idx += len;
+	BUG_ON(*idx > buf_len + 1);
+	return &buf[*idx - len];
+}
+
+#define IP_VS_DBG_BUF(level, msg...)			\
+    do {						\
+	    char ip_vs_dbg_buf[160];			\
+	    int ip_vs_dbg_idx = 0;			\
+	    if (level <= ip_vs_get_debug_level())	\
+		    printk(KERN_DEBUG "IPVS: " msg);	\
+    } while (0)
+#define IP_VS_ERR_BUF(msg...)				\
+    do {						\
+	    char ip_vs_dbg_buf[160];			\
+	    int ip_vs_dbg_idx = 0;			\
+	    printk(KERN_ERR "IPVS: " msg);		\
+    } while (0)
+
+/* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */
+#define IP_VS_DBG_ADDR(af, addr)			\
+    ip_vs_dbg_addr(af, ip_vs_dbg_buf,			\
+		   sizeof(ip_vs_dbg_buf), addr,		\
+		   &ip_vs_dbg_idx)
+
 #define IP_VS_DBG(level, msg...)			\
     do {						\
 	    if (level <= ip_vs_get_debug_level())	\
@@ -100,6 +140,8 @@ extern int ip_vs_get_debug_level(void);
 		pp->debug_packet(pp, skb, ofs, msg);	\
     } while (0)
 #else	/* NO DEBUGGING at ALL */
+#define IP_VS_DBG_BUF(level, msg...)  do {} while (0)
+#define IP_VS_ERR_BUF(msg...)  do {} while (0)
 #define IP_VS_DBG(level, msg...)  do {} while (0)
 #define IP_VS_DBG_RL(msg...)  do {} while (0)
 #define IP_VS_DBG_PKT(level, pp, skb, ofs, msg)		do {} while (0)
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (3 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 04/25] IPVS: Add debug macros for v4 and v6 address output Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  6:06   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 06/25] IPVS: Convert __ip_vs_svc_get() and __ip_vs_fwm_get() Julius Volz
                   ` (20 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add extended internal versions of struct ip_vs_service_user and struct
ip_vs_dest_user (the originals can't be modified as they are part
of the old sockopt interface). Adjust ip_vs_ctl.c to work with the new
data structures and add some minor AF-awareness.

Signed-off-by: Julius Volz <juliusv@google.com>

 2 files changed, 129 insertions(+), 48 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 45a7458..9657bd4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -400,6 +400,45 @@ struct ip_vs_conn {
 
 
 /*
+ *	Extended internal versions of struct ip_vs_service_user and
+ *	ip_vs_dest_user for IPv6 support.
+ *
+ *	We need these to conveniently pass around service and destination
+ *	options, but unfortunately, we also need to keep the old definitions to
+ *	maintain userspace backwards compatibility for the setsockopt interface.
+ */
+struct ip_vs_service_user_kern {
+	/* virtual service addresses */
+	u_int16_t		af;
+	u_int16_t		protocol;
+	union nf_inet_addr	addr;		/* virtual ip address */
+	__be16			port;
+	u_int32_t		fwmark;		/* firwall mark of service */
+
+	/* virtual service options */
+	char			*sched_name;
+	unsigned		flags;		/* virtual service flags */
+	unsigned		timeout;	/* persistent timeout in sec */
+	__be32			netmask;	/* persistent netmask */
+};
+
+
+struct ip_vs_dest_user_kern {
+	/* destination server address */
+	union nf_inet_addr	addr;
+	__be16			port;
+
+	/* real server options */
+	unsigned		conn_flags;	/* connection flags */
+	int			weight;		/* destination weight */
+
+	/* thresholds for active connections */
+	u_int32_t		u_threshold;	/* upper threshold */
+	u_int32_t		l_threshold;	/* lower threshold */
+};
+
+
+/*
  *	The information about the virtual service offered to the net
  *	and the forwarding entries
  */
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 47644f3..52b3c1e 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -707,7 +707,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
  */
 static void
 __ip_vs_update_dest(struct ip_vs_service *svc,
-		    struct ip_vs_dest *dest, struct ip_vs_dest_user *udest)
+		    struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
 {
 	int conn_flags;
 
@@ -716,7 +716,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
 	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
 
 	/* check if local node and update the flags */
-	if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) {
+	if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
 		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
 			| IP_VS_CONN_F_LOCALNODE;
 	}
@@ -760,7 +760,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
  *	Create a destination for the given service
  */
 static int
-ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
+ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
 	       struct ip_vs_dest **dest_p)
 {
 	struct ip_vs_dest *dest;
@@ -768,7 +768,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
 
 	EnterFunction(2);
 
-	atype = inet_addr_type(&init_net, udest->addr);
+	atype = inet_addr_type(&init_net, udest->addr.ip);
 	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
 		return -EINVAL;
 
@@ -778,11 +778,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
 		return -ENOMEM;
 	}
 
+	dest->af = svc->af;
 	dest->protocol = svc->protocol;
-	dest->vaddr.ip = svc->addr.ip;
+	dest->vaddr = svc->addr;
 	dest->vport = svc->port;
 	dest->vfwmark = svc->fwmark;
-	dest->addr.ip = udest->addr;
+	ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
 	dest->port = udest->port;
 
 	atomic_set(&dest->activeconns, 0);
@@ -807,10 +808,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
  *	Add a destination into an existing service
  */
 static int
-ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
+ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 {
 	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
+	union nf_inet_addr daddr;
 	__be16 dport = udest->port;
 	int ret;
 
@@ -827,10 +828,12 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 		return -ERANGE;
 	}
 
+	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
+
 	/*
 	 * Check if the dest already exists in the list
 	 */
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
 	if (dest != NULL) {
 		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
 		return -EEXIST;
@@ -840,7 +843,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 	 * Check if the dest already exists in the trash and
 	 * is from the same service
 	 */
-	dest = ip_vs_trash_get_dest(svc, daddr, dport);
+	dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
 	if (dest != NULL) {
 		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
 			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
@@ -915,10 +918,10 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
  *	Edit a destination in the given service
  */
 static int
-ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
+ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 {
 	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
+	union nf_inet_addr daddr;
 	__be16 dport = udest->port;
 
 	EnterFunction(2);
@@ -934,10 +937,12 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 		return -ERANGE;
 	}
 
+	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
+
 	/*
 	 *  Lookup the destination list
 	 */
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
 		return -ENOENT;
@@ -1028,15 +1033,15 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
  *	Delete a destination server in the given service
  */
 static int
-ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
+ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 {
 	struct ip_vs_dest *dest;
-	__be32 daddr = udest->addr;
 	__be16 dport = udest->port;
 
 	EnterFunction(2);
 
-	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
+
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
 		return -ENOENT;
@@ -1071,7 +1076,8 @@ ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
  *	Add a service into the service hash table
  */
 static int
-ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
+ip_vs_add_service(struct ip_vs_service_user_kern *u,
+		  struct ip_vs_service **svc_p)
 {
 	int ret = 0;
 	struct ip_vs_scheduler *sched = NULL;
@@ -1100,8 +1106,9 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
 	atomic_set(&svc->usecnt, 1);
 	atomic_set(&svc->refcnt, 0);
 
+	svc->af = u->af;
 	svc->protocol = u->protocol;
-	svc->addr.ip = u->addr;
+	ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
 	svc->port = u->port;
 	svc->fwmark = u->fwmark;
 	svc->flags = u->flags;
@@ -1160,7 +1167,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
  *	Edit a service and bind it with a new scheduler
  */
 static int
-ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u)
+ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 {
 	struct ip_vs_scheduler *sched, *old_sched;
 	int ret = 0;
@@ -1904,14 +1911,44 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
 	[SET_CMDID(IP_VS_SO_SET_ZERO)]		= SERVICE_ARG_LEN,
 };
 
+static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
+				  struct ip_vs_service_user *usvc_compat)
+{
+	usvc->af		= AF_INET;
+	usvc->protocol		= usvc_compat->protocol;
+	usvc->addr.ip		= usvc_compat->addr;
+	usvc->port		= usvc_compat->port;
+	usvc->fwmark		= usvc_compat->fwmark;
+
+	/* Deep copy of sched_name is not needed here */
+	usvc->sched_name	= usvc_compat->sched_name;
+
+	usvc->flags		= usvc_compat->flags;
+	usvc->timeout		= usvc_compat->timeout;
+	usvc->netmask		= usvc_compat->netmask;
+}
+
+static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
+				   struct ip_vs_dest_user *udest_compat)
+{
+	udest->addr.ip		= udest_compat->addr;
+	udest->port		= udest_compat->port;
+	udest->conn_flags	= udest_compat->conn_flags;
+	udest->weight		= udest_compat->weight;
+	udest->u_threshold	= udest_compat->u_threshold;
+	udest->l_threshold	= udest_compat->l_threshold;
+}
+
 static int
 do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 {
 	int ret;
 	unsigned char arg[MAX_ARG_LEN];
-	struct ip_vs_service_user *usvc;
+	struct ip_vs_service_user *usvc_compat;
+	struct ip_vs_service_user_kern usvc;
 	struct ip_vs_service *svc;
-	struct ip_vs_dest_user *udest;
+	struct ip_vs_dest_user *udest_compat;
+	struct ip_vs_dest_user_kern udest;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -1951,35 +1988,40 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 		goto out_unlock;
 	}
 
-	usvc = (struct ip_vs_service_user *)arg;
-	udest = (struct ip_vs_dest_user *)(usvc + 1);
+	usvc_compat = (struct ip_vs_service_user *)arg;
+	udest_compat = (struct ip_vs_dest_user *)(usvc_compat + 1);
+
+	/* We only use the new structs internally, so copy userspace compat
+	 * structs to extended internal versions */
+	ip_vs_copy_usvc_compat(&usvc, usvc_compat);
+	ip_vs_copy_udest_compat(&udest, udest_compat);
 
 	if (cmd == IP_VS_SO_SET_ZERO) {
 		/* if no service address is set, zero counters in all */
-		if (!usvc->fwmark && !usvc->addr && !usvc->port) {
+		if (!usvc.fwmark && !usvc.addr.ip && !usvc.port) {
 			ret = ip_vs_zero_all();
 			goto out_unlock;
 		}
 	}
 
 	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
-	if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) {
+	if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) {
 		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
-			  usvc->protocol, NIPQUAD(usvc->addr),
-			  ntohs(usvc->port), usvc->sched_name);
+			  usvc.protocol, NIPQUAD(usvc.addr.ip),
+			  ntohs(usvc.port), usvc.sched_name);
 		ret = -EFAULT;
 		goto out_unlock;
 	}
 
 	/* Lookup the exact service by <protocol, addr, port> or fwmark */
-	if (usvc->fwmark == 0)
-		svc = __ip_vs_service_get(usvc->protocol,
-					  usvc->addr, usvc->port);
+	if (usvc.fwmark == 0)
+		svc = __ip_vs_service_get(usvc.protocol,
+					  usvc.addr.ip, usvc.port);
 	else
-		svc = __ip_vs_svc_fwm_get(usvc->fwmark);
+		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
 
 	if (cmd != IP_VS_SO_SET_ADD
-	    && (svc == NULL || svc->protocol != usvc->protocol)) {
+	    && (svc == NULL || svc->protocol != usvc.protocol)) {
 		ret = -ESRCH;
 		goto out_unlock;
 	}
@@ -1989,10 +2031,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 		if (svc != NULL)
 			ret = -EEXIST;
 		else
-			ret = ip_vs_add_service(usvc, &svc);
+			ret = ip_vs_add_service(&usvc, &svc);
 		break;
 	case IP_VS_SO_SET_EDIT:
-		ret = ip_vs_edit_service(svc, usvc);
+		ret = ip_vs_edit_service(svc, &usvc);
 		break;
 	case IP_VS_SO_SET_DEL:
 		ret = ip_vs_del_service(svc);
@@ -2003,13 +2045,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 		ret = ip_vs_zero_service(svc);
 		break;
 	case IP_VS_SO_SET_ADDDEST:
-		ret = ip_vs_add_dest(svc, udest);
+		ret = ip_vs_add_dest(svc, &udest);
 		break;
 	case IP_VS_SO_SET_EDITDEST:
-		ret = ip_vs_edit_dest(svc, udest);
+		ret = ip_vs_edit_dest(svc, &udest);
 		break;
 	case IP_VS_SO_SET_DELDEST:
-		ret = ip_vs_del_dest(svc, udest);
+		ret = ip_vs_del_dest(svc, &udest);
 		break;
 	default:
 		ret = -EINVAL;
@@ -2516,7 +2558,7 @@ nla_put_failure:
 	return skb->len;
 }
 
-static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
+static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
 				    struct nlattr *nla, int full_entry)
 {
 	struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
@@ -2536,6 +2578,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
 	if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
 		return -EINVAL;
 
+	usvc->af = nla_get_u16(nla_af);
 	/* For now, only support IPv4 */
 	if (nla_get_u16(nla_af) != AF_INET)
 		return -EAFNOSUPPORT;
@@ -2571,7 +2614,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
 		if (usvc->fwmark)
 			svc = __ip_vs_svc_fwm_get(usvc->fwmark);
 		else
-			svc = __ip_vs_service_get(usvc->protocol, usvc->addr,
+			svc = __ip_vs_service_get(usvc->protocol, usvc->addr.ip,
 						  usvc->port);
 		if (svc) {
 			usvc->flags = svc->flags;
@@ -2582,9 +2625,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
 		/* set new flags from userland */
 		usvc->flags = (usvc->flags & ~flags.mask) |
 			      (flags.flags & flags.mask);
-
-		strlcpy(usvc->sched_name, nla_data(nla_sched),
-			sizeof(usvc->sched_name));
+		usvc->sched_name = nla_data(nla_sched);
 		usvc->timeout = nla_get_u32(nla_timeout);
 		usvc->netmask = nla_get_u32(nla_netmask);
 	}
@@ -2594,7 +2635,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
 
 static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
 {
-	struct ip_vs_service_user usvc;
+	struct ip_vs_service_user_kern usvc;
 	int ret;
 
 	ret = ip_vs_genl_parse_service(&usvc, nla, 0);
@@ -2604,7 +2645,7 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
 	if (usvc.fwmark)
 		return __ip_vs_svc_fwm_get(usvc.fwmark);
 	else
-		return __ip_vs_service_get(usvc.protocol, usvc.addr,
+		return __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
 					   usvc.port);
 }
 
@@ -2704,7 +2745,7 @@ out_err:
 	return skb->len;
 }
 
-static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
+static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
 				 struct nlattr *nla, int full_entry)
 {
 	struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
@@ -2860,8 +2901,8 @@ static int ip_vs_genl_set_config(struct nlattr **attrs)
 static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
 {
 	struct ip_vs_service *svc = NULL;
-	struct ip_vs_service_user usvc;
-	struct ip_vs_dest_user udest;
+	struct ip_vs_service_user_kern usvc;
+	struct ip_vs_dest_user_kern udest;
 	int ret = 0, cmd;
 	int need_full_svc = 0, need_full_dest = 0;
 
@@ -2913,7 +2954,8 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
 
 	/* Lookup the exact service by <protocol, addr, port> or fwmark */
 	if (usvc.fwmark == 0)
-		svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port);
+		svc = __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
+					  usvc.port);
 	else
 		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
 
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 06/25] IPVS: Convert __ip_vs_svc_get() and __ip_vs_fwm_get()
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (4 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 07/25] IPVS: Add v6 support to ip_vs_service_get() Julius Volz
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add support for getting services based on their address family to
__ip_vs_service_get(), __ip_vs_fwm_get() and the helper hash function
ip_vs_svc_hashkey(). Adjust the callers.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 47 insertions(+), 31 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 52b3c1e..aa74d20 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -282,11 +282,19 @@ static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
  *	Returns hash value for virtual service
  */
 static __inline__ unsigned
-ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
+ip_vs_svc_hashkey(int af, unsigned proto, const union nf_inet_addr *addr,
+		  __be16 port)
 {
 	register unsigned porth = ntohs(port);
+	__be32 addr_fold = addr->ip;
 
-	return (proto^ntohl(addr)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+
+	return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
 		& IP_VS_SVC_TAB_MASK;
 }
 
@@ -317,7 +325,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
 		/*
 		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
 		 */
-		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr.ip, svc->port);
+		hash = ip_vs_svc_hashkey(svc->af, svc->protocol, &svc->addr,
+					 svc->port);
 		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
 	} else {
 		/*
@@ -364,16 +373,18 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
  *	Get service by {proto,addr,port} in the service table.
  */
 static __inline__ struct ip_vs_service *
-__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
+__ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
+		    __be16 vport)
 {
 	unsigned hash;
 	struct ip_vs_service *svc;
 
 	/* Check for "full" addressed entries */
-	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
+	hash = ip_vs_svc_hashkey(af, protocol, vaddr, vport);
 
 	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
-		if ((svc->addr.ip == vaddr)
+		if ((svc->af == af)
+		    && ip_vs_addr_equal(af, &svc->addr, vaddr)
 		    && (svc->port == vport)
 		    && (svc->protocol == protocol)) {
 			/* HIT */
@@ -389,7 +400,8 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
 /*
  *	Get service by {fwmark} in the service table.
  */
-static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
+static __inline__ struct ip_vs_service *
+__ip_vs_svc_fwm_get(int af, __u32 fwmark)
 {
 	unsigned hash;
 	struct ip_vs_service *svc;
@@ -398,7 +410,7 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
 	hash = ip_vs_svc_fwm_hashkey(fwmark);
 
 	list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
-		if (svc->fwmark == fwmark) {
+		if (svc->fwmark == fwmark && svc->af == af) {
 			/* HIT */
 			atomic_inc(&svc->usecnt);
 			return svc;
@@ -412,20 +424,20 @@ struct ip_vs_service *
 ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 {
 	struct ip_vs_service *svc;
-
+	union nf_inet_addr _vaddr = { .ip = vaddr };
 	read_lock(&__ip_vs_svc_lock);
 
 	/*
 	 *	Check the table hashed by fwmark first
 	 */
-	if (fwmark && (svc = __ip_vs_svc_fwm_get(fwmark)))
+	if (fwmark && (svc = __ip_vs_svc_fwm_get(AF_INET, fwmark)))
 		goto out;
 
 	/*
 	 *	Check the table hashed by <protocol,addr,port>
 	 *	for "full" addressed entries
 	 */
-	svc = __ip_vs_service_get(protocol, vaddr, vport);
+	svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, vport);
 
 	if (svc == NULL
 	    && protocol == IPPROTO_TCP
@@ -435,7 +447,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 		 * Check if ftp service entry exists, the packet
 		 * might belong to FTP data connections.
 		 */
-		svc = __ip_vs_service_get(protocol, vaddr, FTPPORT);
+		svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, FTPPORT);
 	}
 
 	if (svc == NULL
@@ -443,7 +455,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 		/*
 		 * Check if the catch-all port (port zero) exists
 		 */
-		svc = __ip_vs_service_get(protocol, vaddr, 0);
+		svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, 0);
 	}
 
   out:
@@ -2015,10 +2027,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
 	/* Lookup the exact service by <protocol, addr, port> or fwmark */
 	if (usvc.fwmark == 0)
-		svc = __ip_vs_service_get(usvc.protocol,
-					  usvc.addr.ip, usvc.port);
+		svc = __ip_vs_service_get(usvc.af, usvc.protocol,
+					  &usvc.addr, usvc.port);
 	else
-		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
+		svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
 
 	if (cmd != IP_VS_SO_SET_ADD
 	    && (svc == NULL || svc->protocol != usvc.protocol)) {
@@ -2140,13 +2152,15 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
 			 struct ip_vs_get_dests __user *uptr)
 {
 	struct ip_vs_service *svc;
+	union nf_inet_addr addr = { .ip = get->addr };
 	int ret = 0;
 
 	if (get->fwmark)
-		svc = __ip_vs_svc_fwm_get(get->fwmark);
+		svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark);
 	else
-		svc = __ip_vs_service_get(get->protocol,
-					  get->addr, get->port);
+		svc = __ip_vs_service_get(AF_INET, get->protocol, &addr,
+					  get->port);
+
 	if (svc) {
 		int count = 0;
 		struct ip_vs_dest *dest;
@@ -2281,13 +2295,15 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 	{
 		struct ip_vs_service_entry *entry;
 		struct ip_vs_service *svc;
+		union nf_inet_addr addr;
 
 		entry = (struct ip_vs_service_entry *)arg;
+		addr.ip = entry->addr;
 		if (entry->fwmark)
-			svc = __ip_vs_svc_fwm_get(entry->fwmark);
+			svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark);
 		else
-			svc = __ip_vs_service_get(entry->protocol,
-						  entry->addr, entry->port);
+			svc = __ip_vs_service_get(AF_INET, entry->protocol,
+						  &addr, entry->port);
 		if (svc) {
 			ip_vs_copy_service(entry, svc);
 			if (copy_to_user(user, entry, sizeof(*entry)) != 0)
@@ -2612,10 +2628,10 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
 
 		/* prefill flags from service if it already exists */
 		if (usvc->fwmark)
-			svc = __ip_vs_svc_fwm_get(usvc->fwmark);
+			svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark);
 		else
-			svc = __ip_vs_service_get(usvc->protocol, usvc->addr.ip,
-						  usvc->port);
+			svc = __ip_vs_service_get(usvc->af, usvc->protocol,
+						  &usvc->addr, usvc->port);
 		if (svc) {
 			usvc->flags = svc->flags;
 			ip_vs_service_put(svc);
@@ -2643,10 +2659,10 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
 		return ERR_PTR(ret);
 
 	if (usvc.fwmark)
-		return __ip_vs_svc_fwm_get(usvc.fwmark);
+		return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
 	else
-		return __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
-					   usvc.port);
+		return __ip_vs_service_get(usvc.af, usvc.protocol,
+					   &usvc.addr, usvc.port);
 }
 
 static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
@@ -2954,10 +2970,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
 
 	/* Lookup the exact service by <protocol, addr, port> or fwmark */
 	if (usvc.fwmark == 0)
-		svc = __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
-					  usvc.port);
+		svc = __ip_vs_service_get(usvc.af, usvc.protocol,
+					  &usvc.addr, usvc.port);
 	else
-		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
+		svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
 
 	/* Unless we're adding a new service, the service must already exist */
 	if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 07/25] IPVS: Add v6 support to ip_vs_service_get()
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (5 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 06/25] IPVS: Convert __ip_vs_svc_get() and __ip_vs_fwm_get() Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 08/25] IPVS: Add IPv6 support flag to schedulers Julius Volz
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add support for selecting services based on their address family to
ip_vs_service_get() and adjust the callers.

Signed-off-by: Julius Volz <juliusv@google.com>

 4 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 9657bd4..d653e8b 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -783,7 +783,8 @@ extern struct ip_vs_stats ip_vs_stats;
 extern const struct ctl_path net_vs_ctl_path[];
 
 extern struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+		  const union nf_inet_addr *vaddr, __be16 vport);
 
 static inline void ip_vs_service_put(struct ip_vs_service *svc)
 {
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index aa74d20..151d368 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -421,23 +421,24 @@ __ip_vs_svc_fwm_get(int af, __u32 fwmark)
 }
 
 struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+		  const union nf_inet_addr *vaddr, __be16 vport)
 {
 	struct ip_vs_service *svc;
-	union nf_inet_addr _vaddr = { .ip = vaddr };
+
 	read_lock(&__ip_vs_svc_lock);
 
 	/*
 	 *	Check the table hashed by fwmark first
 	 */
-	if (fwmark && (svc = __ip_vs_svc_fwm_get(AF_INET, fwmark)))
+	if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark)))
 		goto out;
 
 	/*
 	 *	Check the table hashed by <protocol,addr,port>
 	 *	for "full" addressed entries
 	 */
-	svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, vport);
+	svc = __ip_vs_service_get(af, protocol, vaddr, vport);
 
 	if (svc == NULL
 	    && protocol == IPPROTO_TCP
@@ -447,7 +448,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 		 * Check if ftp service entry exists, the packet
 		 * might belong to FTP data connections.
 		 */
-		svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, FTPPORT);
+		svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT);
 	}
 
 	if (svc == NULL
@@ -455,16 +456,16 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 		/*
 		 * Check if the catch-all port (port zero) exists
 		 */
-		svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, 0);
+		svc = __ip_vs_service_get(af, protocol, vaddr, 0);
 	}
 
   out:
 	read_unlock(&__ip_vs_svc_lock);
 
-	IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
-		  fwmark, ip_vs_proto_name(protocol),
-		  NIPQUAD(vaddr), ntohs(vport),
-		  svc?"hit":"not hit");
+	IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
+		      fwmark, ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, vaddr), ntohs(vport),
+		      svc ? "hit" : "not hit");
 
 	return svc;
 }
@@ -605,8 +606,9 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_service *svc;
+	union nf_inet_addr _vaddr = { .ip = vaddr };
 
-	svc = ip_vs_service_get(0, protocol, vaddr, vport);
+	svc = ip_vs_service_get(AF_INET, 0, protocol, &_vaddr, vport);
 	if (!svc)
 		return NULL;
 	dest = ip_vs_lookup_dest(svc, daddr, dport);
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 15860e1..fe93c9e 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -74,16 +74,19 @@ tcp_conn_schedule(struct sk_buff *skb,
 {
 	struct ip_vs_service *svc;
 	struct tcphdr _tcph, *th;
+	struct ip_vs_iphdr iph;
 
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+
+	th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
 	if (th == NULL) {
 		*verdict = NF_DROP;
 		return 0;
 	}
 
 	if (th->syn &&
-	    (svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
-				     ip_hdr(skb)->daddr, th->dest))) {
+	    (svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol,
+				     &iph.daddr, th->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 8dfad5d..5aefdf5 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -80,16 +80,18 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
 {
 	struct ip_vs_service *svc;
 	struct udphdr _udph, *uh;
+	struct ip_vs_iphdr iph;
 
-	uh = skb_header_pointer(skb, ip_hdrlen(skb),
-				sizeof(_udph), &_udph);
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+
+	uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
 	if (uh == NULL) {
 		*verdict = NF_DROP;
 		return 0;
 	}
 
-	if ((svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
-				     ip_hdr(skb)->daddr, uh->dest))) {
+	if ((svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol,
+				     &iph.daddr, uh->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 08/25] IPVS: Add IPv6 support flag to schedulers
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (6 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 07/25] IPVS: Add v6 support to ip_vs_service_get() Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions Julius Volz
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add 'supports_ipv6' flag to struct ip_vs_scheduler to indicate whether a
scheduler supports IPv6. Set the flag to 1 in schedulers that work with
IPv6, 0 otherwise. This flag is checked in a later patch while trying to
add a service with a specific scheduler. Adjust debug in v6-supporting
schedulers to work with both address families.

Signed-off-by: Julius Volz <juliusv@google.com>

 11 files changed, 66 insertions(+), 33 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index d653e8b..881e60a 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -516,6 +516,9 @@ struct ip_vs_scheduler {
 	char			*name;		/* scheduler name */
 	atomic_t		refcnt;		/* reference counter */
 	struct module		*module;	/* THIS_MODULE/NULL */
+#ifdef CONFIG_IP_VS_IPV6
+	int			supports_ipv6;	/* scheduler has IPv6 support */
+#endif
 
 	/* scheduler initializing service */
 	int (*init_service)(struct ip_vs_service *svc);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index 9f9d795..a16943f 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -234,6 +234,9 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
 	.init_service =		ip_vs_dh_init_svc,
 	.done_service =		ip_vs_dh_done_svc,
 	.update_service =	ip_vs_dh_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 69309ed..6ecef35 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -522,6 +522,9 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
 	.init_service =		ip_vs_lblc_init_svc,
 	.done_service =		ip_vs_lblc_done_svc,
 	.schedule =		ip_vs_lblc_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 51c746e..1f75ea8 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -722,6 +722,9 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
 	.init_service =		ip_vs_lblcr_init_svc,
 	.done_service =		ip_vs_lblcr_done_svc,
 	.schedule =		ip_vs_lblcr_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index 551d293..b69f808 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)
 	}
 
 	if (least)
-	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->inactconns));
+	IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d inactconns %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->inactconns));
 
 	return least;
 }
@@ -81,6 +81,9 @@ static struct ip_vs_scheduler ip_vs_lc_scheduler = {
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.schedule =		ip_vs_lc_schedule,
 };
 
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index aa0e32a..9a2d803 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)
 		return NULL;
 
   out:
-	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "NQ: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 
 	return least;
 }
@@ -116,6 +116,9 @@ static struct ip_vs_scheduler ip_vs_nq_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.schedule =		ip_vs_nq_schedule,
 };
 
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index 27f0b62..a22195f 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)
   out:
 	svc->sched_data = q;
 	write_unlock(&svc->sched_lock);
-	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
-		  atomic_read(&dest->activeconns),
-		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
+	IP_VS_DBG_BUF(6, "RR: server %s:%u "
+		      "activeconns %d refcnt %d weight %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+		      atomic_read(&dest->activeconns),
+		      atomic_read(&dest->refcnt), atomic_read(&dest->weight));
 
 	return dest;
 }
@@ -89,6 +89,9 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = {
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.init_service =		ip_vs_rr_init_svc,
 	.update_service =	ip_vs_rr_update_svc,
 	.schedule =		ip_vs_rr_schedule,
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 38b574b..7d2f22f 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)
 		}
 	}
 
-	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "SED: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 
 	return least;
 }
@@ -118,6 +118,9 @@ static struct ip_vs_scheduler ip_vs_sed_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.schedule =		ip_vs_sed_schedule,
 };
 
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index c9e54e2..1d96de2 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -231,6 +231,9 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list	 =		LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	0,
+#endif
 	.init_service =		ip_vs_sh_init_svc,
 	.done_service =		ip_vs_sh_done_svc,
 	.update_service =	ip_vs_sh_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index 09fd993..8c596e7 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)
 		}
 	}
 
-	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "WLC: server %s:%u "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 
 	return least;
 }
@@ -106,6 +106,9 @@ static struct ip_vs_scheduler ip_vs_wlc_scheduler =
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.schedule =		ip_vs_wlc_schedule,
 };
 
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 19c49b2..7ea92fe 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)
 		}
 	}
 
-	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
-		  "activeconns %d refcnt %d weight %d\n",
-		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
-		  atomic_read(&dest->activeconns),
-		  atomic_read(&dest->refcnt),
-		  atomic_read(&dest->weight));
+	IP_VS_DBG_BUF(6, "WRR: server %s:%u "
+		      "activeconns %d refcnt %d weight %d\n",
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+		      atomic_read(&dest->activeconns),
+		      atomic_read(&dest->refcnt),
+		      atomic_read(&dest->weight));
 
   out:
 	write_unlock(&svc->sched_lock);
@@ -213,6 +213,9 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+	.supports_ipv6 =	1,
+#endif
 	.init_service =		ip_vs_wrr_init_svc,
 	.done_service =		ip_vs_wrr_done_svc,
 	.update_service =	ip_vs_wrr_update_svc,
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (7 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 08/25] IPVS: Add IPv6 support flag to schedulers Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  6:26   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 10/25] IPVS: Add protocol debug functions for IPv6 Julius Volz
                   ` (16 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add 'af' arguments to conn_schedule(), conn_in_get(), conn_out_get() and
csum_check() function pointers in struct ip_vs_protocol. Extend the
respective functions for TCP, UDP, AH and ESP and adjust the callers.

The changes in the callers need to be somewhat extensive, since they now
need to pass a filled out struct ip_vs_iphdr * to the modified functions
instead of a struct iphdr *.

Signed-off-by: Julius Volz <juliusv@google.com>

 5 files changed, 173 insertions(+), 126 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 881e60a..3305d1b 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -296,21 +296,23 @@ struct ip_vs_protocol {
 
 	void (*exit)(struct ip_vs_protocol *pp);
 
-	int (*conn_schedule)(struct sk_buff *skb,
+	int (*conn_schedule)(int af, struct sk_buff *skb,
 			     struct ip_vs_protocol *pp,
 			     int *verdict, struct ip_vs_conn **cpp);
 
 	struct ip_vs_conn *
-	(*conn_in_get)(const struct sk_buff *skb,
+	(*conn_in_get)(int af,
+		       const struct sk_buff *skb,
 		       struct ip_vs_protocol *pp,
-		       const struct iphdr *iph,
+		       const struct ip_vs_iphdr *iph,
 		       unsigned int proto_off,
 		       int inverse);
 
 	struct ip_vs_conn *
-	(*conn_out_get)(const struct sk_buff *skb,
+	(*conn_out_get)(int af,
+			const struct sk_buff *skb,
 			struct ip_vs_protocol *pp,
-			const struct iphdr *iph,
+			const struct ip_vs_iphdr *iph,
 			unsigned int proto_off,
 			int inverse);
 
@@ -320,7 +322,8 @@ struct ip_vs_protocol {
 	int (*dnat_handler)(struct sk_buff *skb,
 			    struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
 
-	int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
+	int (*csum_check)(int af, struct sk_buff *skb,
+			  struct ip_vs_protocol *pp);
 
 	const char *(*state_name)(int state);
 
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index a07e5b7..43d7eb2 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -572,6 +572,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
 	struct iphdr *iph;
 	struct icmphdr	_icmph, *ic;
 	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
 	struct ip_vs_conn *cp;
 	struct ip_vs_protocol *pp;
 	unsigned int offset, ihl, verdict;
@@ -627,8 +628,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
 
 	offset += cih->ihl * 4;
 
+	ip_vs_fill_iphdr(AF_INET, cih, &ciph);
 	/* The embedded headers contain source and dest in reverse order */
-	cp = pp->conn_out_get(skb, pp, cih, offset, 1);
+	cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
 	if (!cp)
 		return NF_ACCEPT;
 
@@ -686,43 +688,41 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 	  const struct net_device *in, const struct net_device *out,
 	  int (*okfn)(struct sk_buff *))
 {
-	struct iphdr	*iph;
+	struct ip_vs_iphdr iph;
 	struct ip_vs_protocol *pp;
 	struct ip_vs_conn *cp;
-	int ihl;
 
 	EnterFunction(11);
 
 	if (skb->ipvs_property)
 		return NF_ACCEPT;
 
-	iph = ip_hdr(skb);
-	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	if (unlikely(iph.protocol == IPPROTO_ICMP)) {
 		int related, verdict = ip_vs_out_icmp(skb, &related);
 
 		if (related)
 			return verdict;
-		iph = ip_hdr(skb);
+		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
 	}
 
-	pp = ip_vs_proto_get(iph->protocol);
+	pp = ip_vs_proto_get(iph.protocol);
 	if (unlikely(!pp))
 		return NF_ACCEPT;
 
 	/* reassemble IP fragments */
-	if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) &&
+	if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
 		     !pp->dont_defrag)) {
 		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
 			return NF_STOLEN;
-		iph = ip_hdr(skb);
-	}
 
-	ihl = iph->ihl << 2;
+		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	}
 
 	/*
 	 * Check if the packet belongs to an existing entry
 	 */
-	cp = pp->conn_out_get(skb, pp, iph, ihl, 0);
+	cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		if (sysctl_ip_vs_nat_icmp_send &&
@@ -730,18 +730,18 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 		     pp->protocol == IPPROTO_UDP)) {
 			__be16 _ports[2], *pptr;
 
-			pptr = skb_header_pointer(skb, ihl,
+			pptr = skb_header_pointer(skb, iph.len,
 						  sizeof(_ports), _ports);
 			if (pptr == NULL)
 				return NF_ACCEPT;	/* Not for me */
-			if (ip_vs_lookup_real_service(iph->protocol,
-						      iph->saddr, pptr[0])) {
+			if (ip_vs_lookup_real_service(iph.protocol,
+						      iph.saddr.ip, pptr[0])) {
 				/*
 				 * Notify the real server: there is no
 				 * existing entry if it is not RST
 				 * packet or not TCP packet.
 				 */
-				if (iph->protocol != IPPROTO_TCP
+				if (iph.protocol != IPPROTO_TCP
 				    || !is_tcp_reset(skb)) {
 					icmp_send(skb,ICMP_DEST_UNREACH,
 						  ICMP_PORT_UNREACH, 0);
@@ -756,7 +756,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 
 	IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
 
-	if (!skb_make_writable(skb, ihl))
+	if (!skb_make_writable(skb, iph.len))
 		goto drop;
 
 	/* mangle the packet */
@@ -804,6 +804,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
 	struct iphdr *iph;
 	struct icmphdr	_icmph, *ic;
 	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
 	struct ip_vs_conn *cp;
 	struct ip_vs_protocol *pp;
 	unsigned int offset, ihl, verdict;
@@ -860,8 +861,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
 
 	offset += cih->ihl * 4;
 
+	ip_vs_fill_iphdr(AF_INET, cih, &ciph);
 	/* The embedded headers contain source and dest in reverse order */
-	cp = pp->conn_in_get(skb, pp, cih, offset, 1);
+	cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
 	if (!cp)
 		return NF_ACCEPT;
 
@@ -897,11 +899,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 	 const struct net_device *in, const struct net_device *out,
 	 int (*okfn)(struct sk_buff *))
 {
-	struct iphdr	*iph;
+	struct ip_vs_iphdr iph;
 	struct ip_vs_protocol *pp;
 	struct ip_vs_conn *cp;
 	int ret, restart;
-	int ihl;
+
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
 
 	/*
 	 *	Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@@ -909,38 +912,35 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 	 */
 	if (unlikely(skb->pkt_type != PACKET_HOST
 		     || skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
-		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
-			  skb->pkt_type,
-			  ip_hdr(skb)->protocol,
-			  NIPQUAD(ip_hdr(skb)->daddr));
+		IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
+			      skb->pkt_type,
+			      iph.protocol,
+			      IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
 		return NF_ACCEPT;
 	}
 
-	iph = ip_hdr(skb);
-	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
+	if (unlikely(iph.protocol == IPPROTO_ICMP)) {
 		int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
 
 		if (related)
 			return verdict;
-		iph = ip_hdr(skb);
+		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
 	}
 
 	/* Protocol supported? */
-	pp = ip_vs_proto_get(iph->protocol);
+	pp = ip_vs_proto_get(iph.protocol);
 	if (unlikely(!pp))
 		return NF_ACCEPT;
 
-	ihl = iph->ihl << 2;
-
 	/*
 	 * Check if the packet belongs to an existing connection entry
 	 */
-	cp = pp->conn_in_get(skb, pp, iph, ihl, 0);
+	cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		int v;
 
-		if (!pp->conn_schedule(skb, pp, &v, &cp))
+		if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
 			return v;
 	}
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
index 3f9ebd7..899df2e 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 {
 
 
 static struct ip_vs_conn *
-ah_esp_conn_in_get(const struct sk_buff *skb,
-		   struct ip_vs_protocol *pp,
-		   const struct iphdr *iph,
-		   unsigned int proto_off,
-		   int inverse)
+ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+	           const struct ip_vs_iphdr *iph, unsigned int proto_off,
+	           int inverse)
 {
 	struct ip_vs_conn *cp;
 
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->saddr,
+				       iph->saddr.ip,
 				       htons(PORT_ISAKMP),
-				       iph->daddr,
+				       iph->daddr.ip,
 				       htons(PORT_ISAKMP));
 	} else {
 		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr,
+				       iph->daddr.ip,
 				       htons(PORT_ISAKMP),
-				       iph->saddr,
+				       iph->saddr.ip,
 				       htons(PORT_ISAKMP));
 	}
 
@@ -66,12 +64,12 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
 		 * We are not sure if the packet is from our
 		 * service, so our conn_schedule hook should return NF_ACCEPT
 		 */
-		IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
+		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
+			      "%s%s %s->%s\n",
+			      inverse ? "ICMP+" : "",
+			      pp->name,
+			      IP_VS_DBG_ADDR(af, &iph->saddr),
+			      IP_VS_DBG_ADDR(af, &iph->daddr));
 	}
 
 	return cp;
@@ -79,32 +77,35 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
 
 
 static struct ip_vs_conn *
-ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		    const struct iphdr *iph, unsigned int proto_off, int inverse)
+ah_esp_conn_out_get(int af, const struct sk_buff *skb,
+		    struct ip_vs_protocol *pp,
+	            const struct ip_vs_iphdr *iph,
+		    unsigned int proto_off,
+	            int inverse)
 {
 	struct ip_vs_conn *cp;
 
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->saddr,
+					iph->saddr.ip,
 					htons(PORT_ISAKMP),
-					iph->daddr,
+					iph->daddr.ip,
 					htons(PORT_ISAKMP));
 	} else {
 		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr,
+					iph->daddr.ip,
 					htons(PORT_ISAKMP),
-					iph->saddr,
+					iph->saddr.ip,
 					htons(PORT_ISAKMP));
 	}
 
 	if (!cp) {
-		IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet "
-			  "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
-			  inverse ? "ICMP+" : "",
-			  pp->name,
-			  NIPQUAD(iph->saddr),
-			  NIPQUAD(iph->daddr));
+		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
+			      "%s%s %s->%s\n",
+			      inverse ? "ICMP+" : "",
+			      pp->name,
+			      IP_VS_DBG_ADDR(af, &iph->saddr),
+			      IP_VS_DBG_ADDR(af, &iph->daddr));
 	}
 
 	return cp;
@@ -112,8 +113,7 @@ ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-ah_esp_conn_schedule(struct sk_buff *skb,
-		     struct ip_vs_protocol *pp,
+ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		     int *verdict, struct ip_vs_conn **cpp)
 {
 	/*
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index fe93c9e..9211afa 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -25,8 +25,9 @@
 
 
 static struct ip_vs_conn *
-tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
+tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		int inverse)
 {
 	__be16 _ports[2], *pptr;
 
@@ -36,18 +37,19 @@ tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 	if (likely(!inverse)) {
 		return ip_vs_conn_in_get(iph->protocol,
-					 iph->saddr, pptr[0],
-					 iph->daddr, pptr[1]);
+					 iph->saddr.ip, pptr[0],
+					 iph->daddr.ip, pptr[1]);
 	} else {
 		return ip_vs_conn_in_get(iph->protocol,
-					 iph->daddr, pptr[1],
-					 iph->saddr, pptr[0]);
+					 iph->daddr.ip, pptr[1],
+					 iph->saddr.ip, pptr[0]);
 	}
 }
 
 static struct ip_vs_conn *
-tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
+tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		 int inverse)
 {
 	__be16 _ports[2], *pptr;
 
@@ -57,26 +59,25 @@ tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 	if (likely(!inverse)) {
 		return ip_vs_conn_out_get(iph->protocol,
-					  iph->saddr, pptr[0],
-					  iph->daddr, pptr[1]);
+					  iph->saddr.ip, pptr[0],
+					  iph->daddr.ip, pptr[1]);
 	} else {
 		return ip_vs_conn_out_get(iph->protocol,
-					  iph->daddr, pptr[1],
-					  iph->saddr, pptr[0]);
+					  iph->daddr.ip, pptr[1],
+					  iph->saddr.ip, pptr[0]);
 	}
 }
 
 
 static int
-tcp_conn_schedule(struct sk_buff *skb,
-		  struct ip_vs_protocol *pp,
+tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		  int *verdict, struct ip_vs_conn **cpp)
 {
 	struct ip_vs_service *svc;
 	struct tcphdr _tcph, *th;
 	struct ip_vs_iphdr iph;
 
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 
 	th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
 	if (th == NULL) {
@@ -85,8 +86,8 @@ tcp_conn_schedule(struct sk_buff *skb,
 	}
 
 	if (th->syn &&
-	    (svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol,
-				     &iph.daddr, th->dest))) {
+	    (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
+				     th->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -136,7 +137,7 @@ tcp_snat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
+		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
 			return 0;
 
 		/* Call application helper if needed */
@@ -182,7 +183,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
+		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
 			return 0;
 
 		/*
@@ -219,21 +220,43 @@ tcp_dnat_handler(struct sk_buff *skb,
 
 
 static int
-tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
-	const unsigned int tcphoff = ip_hdrlen(skb);
+	unsigned int tcphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
 
 	switch (skb->ip_summed) {
 	case CHECKSUM_NONE:
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
 	case CHECKSUM_COMPLETE:
-		if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
-				      skb->len - tcphoff,
-				      ip_hdr(skb)->protocol, skb->csum)) {
-			IP_VS_DBG_RL_PKT(0, pp, skb, 0,
-					 "Failed checksum for");
-			return 0;
-		}
+#ifdef CONFIG_IP_VS_IPV6
+		if (af == AF_INET6) {
+			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+					    &ipv6_hdr(skb)->daddr,
+					    skb->len - tcphoff,
+					    ipv6_hdr(skb)->nexthdr,
+					    skb->csum)) {
+				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+						 "Failed checksum for");
+				return 0;
+			}
+		} else
+#endif
+			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+					      ip_hdr(skb)->daddr,
+					      skb->len - tcphoff,
+					      ip_hdr(skb)->protocol,
+					      skb->csum)) {
+				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+						 "Failed checksum for");
+				return 0;
+			}
 		break;
 	default:
 		/* No need to checksum. */
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 5aefdf5..5d9e684 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -24,8 +24,9 @@
 #include <net/ip.h>
 
 static struct ip_vs_conn *
-udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
+udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		int inverse)
 {
 	struct ip_vs_conn *cp;
 	__be16 _ports[2], *pptr;
@@ -36,12 +37,12 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->saddr, pptr[0],
-				       iph->daddr, pptr[1]);
+				       iph->saddr.ip, pptr[0],
+				       iph->daddr.ip, pptr[1]);
 	} else {
 		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->daddr, pptr[1],
-				       iph->saddr, pptr[0]);
+				       iph->daddr.ip, pptr[1],
+				       iph->saddr.ip, pptr[0]);
 	}
 
 	return cp;
@@ -49,25 +50,25 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static struct ip_vs_conn *
-udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
+udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
+		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
+		 int inverse)
 {
 	struct ip_vs_conn *cp;
 	__be16 _ports[2], *pptr;
 
-	pptr = skb_header_pointer(skb, ip_hdrlen(skb),
-				  sizeof(_ports), _ports);
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
 	if (pptr == NULL)
 		return NULL;
 
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->saddr, pptr[0],
-					iph->daddr, pptr[1]);
+					iph->saddr.ip, pptr[0],
+					iph->daddr.ip, pptr[1]);
 	} else {
 		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->daddr, pptr[1],
-					iph->saddr, pptr[0]);
+					iph->daddr.ip, pptr[1],
+					iph->saddr.ip, pptr[0]);
 	}
 
 	return cp;
@@ -75,14 +76,14 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
+udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		  int *verdict, struct ip_vs_conn **cpp)
 {
 	struct ip_vs_service *svc;
 	struct udphdr _udph, *uh;
 	struct ip_vs_iphdr iph;
 
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 
 	uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
 	if (uh == NULL) {
@@ -90,8 +91,8 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		return 0;
 	}
 
-	if ((svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol,
-				     &iph.daddr, uh->dest))) {
+	if ((svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
+				     uh->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -142,7 +143,7 @@ udp_snat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
+		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
 			return 0;
 
 		/*
@@ -194,7 +195,7 @@ udp_dnat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(skb, pp))
+		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
 			return 0;
 
 		/*
@@ -233,10 +234,17 @@ udp_dnat_handler(struct sk_buff *skb,
 
 
 static int
-udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
 	struct udphdr _udph, *uh;
-	const unsigned int udphoff = ip_hdrlen(skb);
+	unsigned int udphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
 
 	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
 	if (uh == NULL)
@@ -248,15 +256,28 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
 			skb->csum = skb_checksum(skb, udphoff,
 						 skb->len - udphoff, 0);
 		case CHECKSUM_COMPLETE:
-			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
-					      ip_hdr(skb)->daddr,
-					      skb->len - udphoff,
-					      ip_hdr(skb)->protocol,
-					      skb->csum)) {
-				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
-						 "Failed checksum for");
-				return 0;
-			}
+#ifdef CONFIG_IP_VS_IPV6
+			if (af == AF_INET6) {
+				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						    &ipv6_hdr(skb)->daddr,
+						    skb->len - udphoff,
+						    ipv6_hdr(skb)->nexthdr,
+						    skb->csum)) {
+					IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+							 "Failed checksum for");
+					return 0;
+				}
+			} else
+#endif
+				if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+						      ip_hdr(skb)->daddr,
+						      skb->len - udphoff,
+						      ip_hdr(skb)->protocol,
+						      skb->csum)) {
+					IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+							 "Failed checksum for");
+					return 0;
+				}
 			break;
 		default:
 			/* No need to checksum. */
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 10/25] IPVS: Add protocol debug functions for IPv6
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (8 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 11/25] IPVS: Extend protocol DNAT/SNAT and state handlers Julius Volz
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add protocol (TCP, UDP, AH, ESP) debug functions for IPv6 packet debug
output.

Signed-off-by: Julius Volz <juliusv@google.com>

 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 6099a88..50f6215 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -152,10 +152,10 @@ const char * ip_vs_state_name(__u16 proto, int state)
 
 
 void
-ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
-			  const struct sk_buff *skb,
-			  int offset,
-			  const char *msg)
+ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
+			     const struct sk_buff *skb,
+			     int offset,
+			     const char *msg)
 {
 	char buf[128];
 	struct iphdr _iph, *ih;
@@ -189,6 +189,61 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+void
+ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
+			     const struct sk_buff *skb,
+			     int offset,
+			     const char *msg)
+{
+	char buf[192];
+	struct ipv6hdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else if (ih->nexthdr == IPPROTO_FRAGMENT)
+		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT " frag",
+			pp->name, NIP6(ih->saddr),
+			NIP6(ih->daddr));
+	else {
+		__be16 _ports[2], *pptr;
+
+		pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
+					  sizeof(_ports), _ports);
+		if (pptr == NULL)
+			sprintf(buf, "%s TRUNCATED " NIP6_FMT "->" NIP6_FMT,
+				pp->name,
+				NIP6(ih->saddr),
+				NIP6(ih->daddr));
+		else
+			sprintf(buf, "%s " NIP6_FMT ":%u->" NIP6_FMT ":%u",
+				pp->name,
+				NIP6(ih->saddr),
+				ntohs(pptr[0]),
+				NIP6(ih->daddr),
+				ntohs(pptr[1]));
+	}
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+#endif
+
+
+void
+ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
+			  const struct sk_buff *skb,
+			  int offset,
+			  const char *msg)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (skb->protocol == __constant_htons(ETH_P_IPV6))
+		ip_vs_tcpudp_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		ip_vs_tcpudp_debug_packet_v4(pp, skb, offset, msg);
+}
+
 
 int __init ip_vs_protocol_init(void)
 {
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
index 899df2e..86dc06e 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
@@ -125,8 +125,8 @@ ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static void
-ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
-		    int offset, const char *msg)
+ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		       int offset, const char *msg)
 {
 	char buf[256];
 	struct iphdr _iph, *ih;
@@ -142,6 +142,38 @@ ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static void
+ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		       int offset, const char *msg)
+{
+	char buf[256];
+	struct ipv6hdr _iph, *ih;
+
+	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
+	if (ih == NULL)
+		sprintf(buf, "%s TRUNCATED", pp->name);
+	else
+		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT,
+			pp->name, NIP6(ih->saddr),
+			NIP6(ih->daddr));
+
+	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+}
+#endif
+
+static void
+ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+		    int offset, const char *msg)
+{
+#ifdef CONFIG_IP_VS_IPV6
+	if (skb->protocol == __constant_htons(ETH_P_IPV6))
+		ah_esp_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		ah_esp_debug_packet_v4(pp, skb, offset, msg);
+}
+
 
 static void ah_esp_init(struct ip_vs_protocol *pp)
 {
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 11/25] IPVS: Extend protocol DNAT/SNAT and state handlers
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (9 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 10/25] IPVS: Add protocol debug functions for IPv6 Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections Julius Volz
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Extend protocol DNAT/SNAT and state handlers to work with IPv6. Also
change/introduce new checksumming helper functions for this.

Signed-off-by: Julius Volz <juliusv@google.com>

 3 files changed, 142 insertions(+), 36 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 3305d1b..15f1a48 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -904,6 +904,17 @@ static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
 	return csum_partial((char *) diff, sizeof(diff), oldsum);
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new,
+					__wsum oldsum)
+{
+	__be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0],
+			    new[3],  new[2],  new[1],  new[0] };
+
+	return csum_partial((char *) diff, sizeof(diff), oldsum);
+}
+#endif
+
 static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
 {
 	__be16 diff[2] = { ~old, new };
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 9211afa..3daae43 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -114,11 +114,21 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static inline void
-tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
+tcp_fast_csum_update(int af, struct tcphdr *tcph,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
 		     __be16 oldport, __be16 newport)
 {
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		tcph->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(tcph->check))));
+	else
+#endif
 	tcph->check =
-		csum_fold(ip_vs_check_diff4(oldip, newip,
+		csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
 				 ip_vs_check_diff2(oldport, newport,
 						~csum_unfold(tcph->check))));
 }
@@ -129,7 +139,14 @@ tcp_snat_handler(struct sk_buff *skb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct tcphdr *tcph;
-	const unsigned int tcphoff = ip_hdrlen(skb);
+	unsigned int tcphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
 
 	/* csum_check requires unshared skb */
 	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -137,7 +154,7 @@ tcp_snat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/* Call application helper if needed */
@@ -145,13 +162,13 @@ tcp_snat_handler(struct sk_buff *skb,
 			return 0;
 	}
 
-	tcph = (void *)ip_hdr(skb) + tcphoff;
+	tcph = (void *)skb_network_header(skb) + tcphoff;
 	tcph->source = cp->vport;
 
 	/* Adjust TCP checksums */
 	if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->daddr.ip, cp->vaddr.ip,
+		tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
 				     cp->dport, cp->vport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -159,9 +176,20 @@ tcp_snat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		tcph->check = 0;
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
-						skb->len - tcphoff,
-						cp->protocol, skb->csum);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			tcph->check = csum_ipv6_magic(&cp->vaddr.in6,
+						      &cp->caddr.in6,
+						      skb->len - tcphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			tcph->check = csum_tcpudp_magic(cp->vaddr.ip,
+							cp->caddr.ip,
+							skb->len - tcphoff,
+							cp->protocol,
+							skb->csum);
+
 		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
 			  pp->name, tcph->check,
 			  (char*)&(tcph->check) - (char*)tcph);
@@ -175,7 +203,14 @@ tcp_dnat_handler(struct sk_buff *skb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct tcphdr *tcph;
-	const unsigned int tcphoff = ip_hdrlen(skb);
+	unsigned int tcphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		tcphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		tcphoff = ip_hdrlen(skb);
 
 	/* csum_check requires unshared skb */
 	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
@@ -183,7 +218,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -194,7 +229,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 			return 0;
 	}
 
-	tcph = (void *)ip_hdr(skb) + tcphoff;
+	tcph = (void *)skb_network_header(skb) + tcphoff;
 	tcph->dest = cp->dport;
 
 	/*
@@ -202,7 +237,7 @@ tcp_dnat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
-		tcp_fast_csum_update(tcph, cp->vaddr.ip, cp->daddr.ip,
+		tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
 				     cp->vport, cp->dport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -210,9 +245,19 @@ tcp_dnat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		tcph->check = 0;
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		tcph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
-						skb->len - tcphoff,
-						cp->protocol, skb->csum);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			tcph->check = csum_ipv6_magic(&cp->caddr.in6,
+						      &cp->daddr.in6,
+						      skb->len - tcphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			tcph->check = csum_tcpudp_magic(cp->caddr.ip,
+							cp->daddr.ip,
+							skb->len - tcphoff,
+							cp->protocol,
+							skb->csum);
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 	return 1;
@@ -487,7 +532,13 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
 {
 	struct tcphdr _tcph, *th;
 
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
+#ifdef CONFIG_IP_VS_IPV6
+	int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
+#else
+	int ihl = ip_hdrlen(skb);
+#endif
+
+	th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);
 	if (th == NULL)
 		return 0;
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 5d9e684..fabe9ba 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -119,13 +119,23 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static inline void
-udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
+udp_fast_csum_update(int af, struct udphdr *uhdr,
+		     const union nf_inet_addr *oldip,
+		     const union nf_inet_addr *newip,
 		     __be16 oldport, __be16 newport)
 {
-	uhdr->check =
-		csum_fold(ip_vs_check_diff4(oldip, newip,
-				 ip_vs_check_diff2(oldport, newport,
-					~csum_unfold(uhdr->check))));
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		uhdr->check =
+			csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(uhdr->check))));
+	else
+#endif
+		uhdr->check =
+			csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+					 ip_vs_check_diff2(oldport, newport,
+						~csum_unfold(uhdr->check))));
 	if (!uhdr->check)
 		uhdr->check = CSUM_MANGLED_0;
 }
@@ -135,7 +145,14 @@ udp_snat_handler(struct sk_buff *skb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct udphdr *udph;
-	const unsigned int udphoff = ip_hdrlen(skb);
+	unsigned int udphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
 
 	/* csum_check requires unshared skb */
 	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -143,7 +160,7 @@ udp_snat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -153,7 +170,7 @@ udp_snat_handler(struct sk_buff *skb,
 			return 0;
 	}
 
-	udph = (void *)ip_hdr(skb) + udphoff;
+	udph = (void *)skb_network_header(skb) + udphoff;
 	udph->source = cp->vport;
 
 	/*
@@ -161,7 +178,7 @@ udp_snat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->daddr.ip, cp->vaddr.ip,
+		udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
 				     cp->dport, cp->vport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -169,9 +186,19 @@ udp_snat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		udph->check = 0;
 		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
-						skb->len - udphoff,
-						cp->protocol, skb->csum);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			udph->check = csum_ipv6_magic(&cp->vaddr.in6,
+						      &cp->caddr.in6,
+						      skb->len - udphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			udph->check = csum_tcpudp_magic(cp->vaddr.ip,
+							cp->caddr.ip,
+							skb->len - udphoff,
+							cp->protocol,
+							skb->csum);
 		if (udph->check == 0)
 			udph->check = CSUM_MANGLED_0;
 		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
@@ -187,7 +214,14 @@ udp_dnat_handler(struct sk_buff *skb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct udphdr *udph;
-	unsigned int udphoff = ip_hdrlen(skb);
+	unsigned int udphoff;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (cp->af == AF_INET6)
+		udphoff = sizeof(struct ipv6hdr);
+	else
+#endif
+		udphoff = ip_hdrlen(skb);
 
 	/* csum_check requires unshared skb */
 	if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -195,7 +229,7 @@ udp_dnat_handler(struct sk_buff *skb,
 
 	if (unlikely(cp->app != NULL)) {
 		/* Some checks before mangling */
-		if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -206,7 +240,7 @@ udp_dnat_handler(struct sk_buff *skb,
 			return 0;
 	}
 
-	udph = (void *)ip_hdr(skb) + udphoff;
+	udph = (void *)skb_network_header(skb) + udphoff;
 	udph->dest = cp->dport;
 
 	/*
@@ -214,7 +248,7 @@ udp_dnat_handler(struct sk_buff *skb,
 	 */
 	if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
-		udp_fast_csum_update(udph, cp->vaddr.ip, cp->daddr.ip,
+		udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
 				     cp->vport, cp->dport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -222,9 +256,19 @@ udp_dnat_handler(struct sk_buff *skb,
 		/* full checksum calculation */
 		udph->check = 0;
 		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
-		udph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
-						skb->len - udphoff,
-						cp->protocol, skb->csum);
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			udph->check = csum_ipv6_magic(&cp->caddr.in6,
+						      &cp->daddr.in6,
+						      skb->len - udphoff,
+						      cp->protocol, skb->csum);
+		else
+#endif
+			udph->check = csum_tcpudp_magic(cp->caddr.ip,
+							cp->daddr.ip,
+							skb->len - udphoff,
+							cp->protocol,
+							skb->csum);
 		if (udph->check == 0)
 			udph->check = CSUM_MANGLED_0;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (10 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 11/25] IPVS: Extend protocol DNAT/SNAT and state handlers Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  6:47   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions Julius Volz
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Extend functions for getting/creating connections and connection
templates for IPv6 support and fix the callers.

Signed-off-by: Julius Volz <juliusv@google.com>

 8 files changed, 209 insertions(+), 165 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 15f1a48..7de9eb4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -642,11 +642,16 @@ enum {
 };
 
 extern struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
 extern struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
 extern struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
 
 /* put back the conn without restarting its timer */
 static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -657,8 +662,9 @@ extern void ip_vs_conn_put(struct ip_vs_conn *cp);
 extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
 
 extern struct ip_vs_conn *
-ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
-	       __be32 daddr, __be16 dport, unsigned flags,
+ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
+	       const union nf_inet_addr *vaddr, __be16 vport,
+	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest);
 extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
 
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index c7f0c2d..664b42c 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)
 /*
  *	Returns hash value for IPVS connection entry
  */
-static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
+static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
+				       const union nf_inet_addr *addr,
+				       __be16 port)
 {
-	return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		return jhash_3words(jhash(addr, 16, ip_vs_conn_rnd),
+				    (__force u32)port, proto, ip_vs_conn_rnd)
+			& IP_VS_CONN_TAB_MASK;
+#endif
+	return jhash_3words((__force u32)addr->ip, (__force u32)port, proto,
+			    ip_vs_conn_rnd)
 		& IP_VS_CONN_TAB_MASK;
 }
 
@@ -131,7 +140,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
 	int ret;
 
 	/* Hash by protocol, client address and port */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
+	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
 
 	ct_write_lock(hash);
 
@@ -162,7 +171,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
 	int ret;
 
 	/* unhash it and decrease its reference counter */
-	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
+	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
 
 	ct_write_lock(hash);
 
@@ -187,20 +196,23 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
  *	d_addr, d_port: pkt dest address (load balancer)
  */
 static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
+	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
+		    s_port == cp->cport && d_port == cp->vport &&
 		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
-		    protocol==cp->protocol) {
+		    protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
 			ct_read_unlock(hash);
@@ -214,39 +226,43 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
 }
 
 struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
 {
 	struct ip_vs_conn *cp;
 
-	cp = __ip_vs_conn_in_get(protocol, s_addr, s_port, d_addr, d_port);
+	cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
 	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
-		cp = __ip_vs_conn_in_get(protocol, s_addr, 0, d_addr, d_port);
+		cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr, d_port);
 
-	IP_VS_DBG(9, "lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  cp?"hit":"not hit");
+	IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      cp ? "hit" : "not hit");
 
 	return cp;
 }
 
 /* Get reference to connection template */
 struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
+	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
+		    s_port == cp->cport && d_port == cp->vport &&
 		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
-		    protocol==cp->protocol) {
+		    protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
 			goto out;
@@ -257,11 +273,11 @@ struct ip_vs_conn *ip_vs_ct_in_get
   out:
 	ct_read_unlock(hash);
 
-	IP_VS_DBG(9, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  cp?"hit":"not hit");
+	IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      cp ? "hit" : "not hit");
 
 	return cp;
 }
@@ -273,7 +289,8 @@ struct ip_vs_conn *ip_vs_ct_in_get
  *	d_addr, d_port: pkt dest address (foreign host)
  */
 struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp, *ret=NULL;
@@ -281,13 +298,15 @@ struct ip_vs_conn *ip_vs_conn_out_get
 	/*
 	 *	Check for "full" addressed entries
 	 */
-	hash = ip_vs_conn_hashkey(protocol, d_addr, d_port);
+	hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (d_addr == cp->caddr.ip && d_port == cp->cport &&
-		    s_port == cp->dport && s_addr == cp->daddr.ip &&
+		if (cp->af == af &&
+		    ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
+		    ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
+		    d_port == cp->cport && s_port == cp->dport &&
 		    protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
@@ -298,11 +317,11 @@ struct ip_vs_conn *ip_vs_conn_out_get
 
 	ct_read_unlock(hash);
 
-	IP_VS_DBG(9, "lookup/out %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
-		  ip_vs_proto_name(protocol),
-		  NIPQUAD(s_addr), ntohs(s_port),
-		  NIPQUAD(d_addr), ntohs(d_port),
-		  ret?"hit":"not hit");
+	IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
+		      ip_vs_proto_name(protocol),
+		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
+		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      ret ? "hit" : "not hit");
 
 	return ret;
 }
@@ -625,8 +644,9 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
  *	Create a new connection entry and hash it into the ip_vs_conn_tab
  */
 struct ip_vs_conn *
-ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
-	       __be32 daddr, __be16 dport, unsigned flags,
+ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
+	       const union nf_inet_addr *vaddr, __be16 vport,
+	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest)
 {
 	struct ip_vs_conn *cp;
@@ -640,12 +660,13 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
 
 	INIT_LIST_HEAD(&cp->c_list);
 	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
+	cp->af		   = af;
 	cp->protocol	   = proto;
-	cp->caddr.ip	   = caddr;
+	ip_vs_addr_copy(af, &cp->caddr, caddr);
 	cp->cport	   = cport;
-	cp->vaddr.ip	   = vaddr;
+	ip_vs_addr_copy(af, &cp->vaddr, vaddr);
 	cp->vport	   = vport;
-	cp->daddr.ip	   = daddr;
+	ip_vs_addr_copy(af, &cp->daddr, daddr);
 	cp->dport          = dport;
 	cp->flags	   = flags;
 	spin_lock_init(&cp->lock);
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 43d7eb2..2d5a433 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -173,19 +173,21 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 		    __be16 ports[2])
 {
 	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
 	__be16  dport;	 /* destination port to forward */
-	__be32  snet;	 /* source network of the client, after masking */
+	union nf_inet_addr snet;	/* source network of the client,
+					   after masking */
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
 
 	/* Mask saddr with the netmask to adjust template granularity */
-	snet = iph->saddr & svc->netmask;
+	snet.ip = iph.saddr.ip & svc->netmask;
 
 	IP_VS_DBG(6, "p-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "
 		  "mnet %u.%u.%u.%u\n",
-		  NIPQUAD(iph->saddr), ntohs(ports[0]),
-		  NIPQUAD(iph->daddr), ntohs(ports[1]),
+		  NIPQUAD(iph.saddr.ip), ntohs(ports[0]),
+		  NIPQUAD(iph.daddr.ip), ntohs(ports[1]),
 		  NIPQUAD(snet));
 
 	/*
@@ -204,11 +206,11 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	if (ports[1] == svc->port) {
 		/* Check if a template already exists */
 		if (svc->port != FTPPORT)
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, ports[1]);
+			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+					     &iph.daddr, ports[1]);
 		else
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, 0);
+			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
 			/*
@@ -228,18 +230,18 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 			 * for ftp service.
 			 */
 			if (svc->port != FTPPORT)
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr,
+				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr,
 						    ports[1],
-						    dest->addr.ip, dest->port,
+						    &dest->addr, dest->port,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			else
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr, 0,
-						    dest->addr.ip, 0,
+				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -258,12 +260,16 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
 		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
 		 */
-		if (svc->fwmark)
-			ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0,
-					       htonl(svc->fwmark), 0);
-		else
-			ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
-					       iph->daddr, 0);
+		if (svc->fwmark) {
+			union nf_inet_addr fwmark = {
+				.all = { 0, 0, 0, htonl(svc->fwmark) }
+			};
+
+			ct = ip_vs_ct_in_get(AF_INET, IPPROTO_IP, &snet, 0,
+					     &fwmark, 0);
+		} else
+			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
 			/*
@@ -282,18 +288,22 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 			/*
 			 * Create a template according to the service
 			 */
-			if (svc->fwmark)
-				ct = ip_vs_conn_new(IPPROTO_IP,
-						    snet, 0,
-						    htonl(svc->fwmark), 0,
-						    dest->addr.ip, 0,
+			if (svc->fwmark) {
+				union nf_inet_addr fwmark = {
+					.all = { 0, 0, 0, htonl(svc->fwmark) }
+				};
+
+				ct = ip_vs_conn_new(AF_INET, IPPROTO_IP,
+						    &snet, 0,
+						    &fwmark, 0,
+						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
-			else
-				ct = ip_vs_conn_new(iph->protocol,
-						    snet, 0,
-						    iph->daddr, 0,
-						    dest->addr.ip, 0,
+			} else
+				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -310,10 +320,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	/*
 	 *    Create a new connection according to the template
 	 */
-	cp = ip_vs_conn_new(iph->protocol,
-			    iph->saddr, ports[0],
-			    iph->daddr, ports[1],
-			    dest->addr.ip, dport,
+	cp = ip_vs_conn_new(AF_INET, iph.protocol,
+			    &iph.saddr, ports[0],
+			    &iph.daddr, ports[1],
+			    &dest->addr, dport,
 			    0,
 			    dest);
 	if (cp == NULL) {
@@ -342,12 +352,12 @@ struct ip_vs_conn *
 ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 {
 	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
 	__be16 _ports[2], *pptr;
 
-	pptr = skb_header_pointer(skb, iph->ihl*4,
-				  sizeof(_ports), _ports);
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
 	if (pptr == NULL)
 		return NULL;
 
@@ -377,10 +387,10 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	/*
 	 *    Create a connection entry.
 	 */
-	cp = ip_vs_conn_new(iph->protocol,
-			    iph->saddr, pptr[0],
-			    iph->daddr, pptr[1],
-			    dest->addr.ip, dest->port?dest->port:pptr[1],
+	cp = ip_vs_conn_new(AF_INET, iph.protocol,
+			    &iph.saddr, pptr[0],
+			    &iph.daddr, pptr[1],
+			    &dest->addr, dest->port ? dest->port : pptr[1],
 			    0,
 			    dest);
 	if (cp == NULL)
@@ -408,10 +418,10 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 		struct ip_vs_protocol *pp)
 {
 	__be16 _ports[2], *pptr;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
+	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
 
-	pptr = skb_header_pointer(skb, iph->ihl*4,
-				  sizeof(_ports), _ports);
+	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
 	if (pptr == NULL) {
 		ip_vs_service_put(svc);
 		return NF_DROP;
@@ -421,7 +431,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 	   and the destination is RTN_UNICAST (and not local), then create
 	   a cache_bypass connection entry */
 	if (sysctl_ip_vs_cache_bypass && svc->fwmark
-	    && (inet_addr_type(&init_net, iph->daddr) == RTN_UNICAST)) {
+	    && (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST)) {
 		int ret, cs;
 		struct ip_vs_conn *cp;
 
@@ -429,9 +439,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 
 		/* create a new connection entry */
 		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
-		cp = ip_vs_conn_new(iph->protocol,
-				    iph->saddr, pptr[0],
-				    iph->daddr, pptr[1],
+		cp = ip_vs_conn_new(AF_INET, iph.protocol,
+				    &iph.saddr, pptr[0],
+				    &iph.daddr, pptr[1],
 				    0, 0,
 				    IP_VS_CONN_F_BYPASS,
 				    NULL);
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index bfe5d70..c56b2bd 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -140,7 +140,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	struct tcphdr *th;
 	char *data, *data_limit;
 	char *start, *end;
-	__be32 from;
+	union nf_inet_addr from;
 	__be16 port;
 	struct ip_vs_conn *n_cp;
 	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
@@ -166,24 +166,24 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 		if (ip_vs_ftp_get_addrport(data, data_limit,
 					   SERVER_STRING,
 					   sizeof(SERVER_STRING)-1, ')',
-					   &from, &port,
+					   &from.ip, &port,
 					   &start, &end) != 1)
 			return 1;
 
 		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
 			  "%u.%u.%u.%u:%d detected\n",
-			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr.ip), 0);
+			  NIPQUAD(from.ip), ntohs(port), NIPQUAD(cp->caddr.ip), 0);
 
 		/*
 		 * Now update or create an connection entry for it
 		 */
-		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
-					  cp->caddr.ip, 0);
+		n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
+					  &cp->caddr, 0);
 		if (!n_cp) {
-			n_cp = ip_vs_conn_new(IPPROTO_TCP,
-					      cp->caddr.ip, 0,
-					      cp->vaddr.ip, port,
-					      from, port,
+			n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
+					      &cp->caddr, 0,
+					      &cp->vaddr, port,
+					      &from, port,
 					      IP_VS_CONN_F_NO_CPORT,
 					      cp->dest);
 			if (!n_cp)
@@ -196,9 +196,9 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 		/*
 		 * Replace the old passive address with the new one
 		 */
-		from = n_cp->vaddr.ip;
+		from.ip = n_cp->vaddr.ip;
 		port = n_cp->vport;
-		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
+		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from.ip),
 			(ntohs(port)>>8)&255, ntohs(port)&255);
 		buf_len = strlen(buf);
 
@@ -243,7 +243,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	struct tcphdr *th;
 	char *data, *data_start, *data_limit;
 	char *start, *end;
-	__be32 to;
+	union nf_inet_addr to;
 	__be16 port;
 	struct ip_vs_conn *n_cp;
 
@@ -291,12 +291,12 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	 */
 	if (ip_vs_ftp_get_addrport(data_start, data_limit,
 				   CLIENT_STRING, sizeof(CLIENT_STRING)-1,
-				   '\r', &to, &port,
+				   '\r', &to.ip, &port,
 				   &start, &end) != 1)
 		return 1;
 
 	IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n",
-		  NIPQUAD(to), ntohs(port));
+		  NIPQUAD(to.ip), ntohs(port));
 
 	/* Passive mode off */
 	cp->app_data = NULL;
@@ -306,16 +306,16 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	 */
 	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
 		  ip_vs_proto_name(iph->protocol),
-		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
+		  NIPQUAD(to.ip), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
 
-	n_cp = ip_vs_conn_in_get(iph->protocol,
-				 to, port,
-				 cp->vaddr.ip, htons(ntohs(cp->vport)-1));
+	n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
+				 &to, port,
+				 &cp->vaddr, htons(ntohs(cp->vport)-1));
 	if (!n_cp) {
-		n_cp = ip_vs_conn_new(IPPROTO_TCP,
-				      to, port,
-				      cp->vaddr.ip, htons(ntohs(cp->vport)-1),
-				      cp->daddr.ip, htons(ntohs(cp->dport)-1),
+		n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
+				      &to, port,
+				      &cp->vaddr, htons(ntohs(cp->vport)-1),
+				      &cp->daddr, htons(ntohs(cp->dport)-1),
 				      0,
 				      cp->dest);
 		if (!n_cp)
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
index 86dc06e..cb366e9 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah_esp.c
@@ -46,16 +46,16 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
 	struct ip_vs_conn *cp;
 
 	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->saddr.ip,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP),
-				       iph->daddr.ip,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr.ip,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP),
-				       iph->saddr.ip,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP));
 	}
 
@@ -86,16 +86,16 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb,
 	struct ip_vs_conn *cp;
 
 	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->saddr.ip,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->saddr,
 					htons(PORT_ISAKMP),
-					iph->daddr.ip,
+					&iph->daddr,
 					htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr.ip,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->daddr,
 					htons(PORT_ISAKMP),
-					iph->saddr.ip,
+					&iph->saddr,
 					htons(PORT_ISAKMP));
 	}
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 3daae43..3da2bb0 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -36,13 +36,13 @@ tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		return NULL;
 
 	if (likely(!inverse)) {
-		return ip_vs_conn_in_get(iph->protocol,
-					 iph->saddr.ip, pptr[0],
-					 iph->daddr.ip, pptr[1]);
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->saddr, pptr[0],
+					 &iph->daddr, pptr[1]);
 	} else {
-		return ip_vs_conn_in_get(iph->protocol,
-					 iph->daddr.ip, pptr[1],
-					 iph->saddr.ip, pptr[0]);
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->daddr, pptr[1],
+					 &iph->saddr, pptr[0]);
 	}
 }
 
@@ -58,13 +58,13 @@ tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		return NULL;
 
 	if (likely(!inverse)) {
-		return ip_vs_conn_out_get(iph->protocol,
-					  iph->saddr.ip, pptr[0],
-					  iph->daddr.ip, pptr[1]);
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->saddr, pptr[0],
+					  &iph->daddr, pptr[1]);
 	} else {
-		return ip_vs_conn_out_get(iph->protocol,
-					  iph->daddr.ip, pptr[1],
-					  iph->saddr.ip, pptr[0]);
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->daddr, pptr[1],
+					  &iph->saddr, pptr[0]);
 	}
 }
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index fabe9ba..0b0b625 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -36,13 +36,13 @@ udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		return NULL;
 
 	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->saddr.ip, pptr[0],
-				       iph->daddr.ip, pptr[1]);
+		cp = ip_vs_conn_in_get(af, iph->protocol,
+				       &iph->saddr, pptr[0],
+				       &iph->daddr, pptr[1]);
 	} else {
-		cp = ip_vs_conn_in_get(iph->protocol,
-				       iph->daddr.ip, pptr[1],
-				       iph->saddr.ip, pptr[0]);
+		cp = ip_vs_conn_in_get(af, iph->protocol,
+				       &iph->daddr, pptr[1],
+				       &iph->saddr, pptr[0]);
 	}
 
 	return cp;
@@ -62,13 +62,13 @@ udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		return NULL;
 
 	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->saddr.ip, pptr[0],
-					iph->daddr.ip, pptr[1]);
+		cp = ip_vs_conn_out_get(af, iph->protocol,
+					&iph->saddr, pptr[0],
+					&iph->daddr, pptr[1]);
 	} else {
-		cp = ip_vs_conn_out_get(iph->protocol,
-					iph->daddr.ip, pptr[1],
-					iph->saddr.ip, pptr[0]);
+		cp = ip_vs_conn_out_get(af, iph->protocol,
+					&iph->daddr, pptr[1],
+					&iph->saddr, pptr[0]);
 	}
 
 	return cp;
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 2cf47b2..3ce1093 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -366,13 +366,17 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 		}
 
 		if (!(flags & IP_VS_CONN_F_TEMPLATE))
-			cp = ip_vs_conn_in_get(s->protocol,
-					       s->caddr, s->cport,
-					       s->vaddr, s->vport);
+			cp = ip_vs_conn_in_get(AF_INET, s->protocol,
+					       (union nf_inet_addr *)&s->caddr,
+					       s->cport,
+					       (union nf_inet_addr *)&s->vaddr,
+					       s->vport);
 		else
-			cp = ip_vs_ct_in_get(s->protocol,
-					       s->caddr, s->cport,
-					       s->vaddr, s->vport);
+			cp = ip_vs_ct_in_get(AF_INET, s->protocol,
+					     (union nf_inet_addr *)&s->caddr,
+					     s->cport,
+					     (union nf_inet_addr *)&s->vaddr,
+					     s->vport);
 		if (!cp) {
 			/*
 			 * Find the appropriate destination for the connection.
@@ -389,10 +393,13 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 				else
 					flags &= ~IP_VS_CONN_F_INACTIVE;
 			}
-			cp = ip_vs_conn_new(s->protocol,
-					    s->caddr, s->cport,
-					    s->vaddr, s->vport,
-					    s->daddr, s->dport,
+			cp = ip_vs_conn_new(AF_INET, s->protocol,
+					    (union nf_inet_addr *)s->caddr,
+					    s->cport,
+					    (union nf_inet_addr *)s->vaddr,
+					    s->vport,
+					    (union nf_inet_addr *)s->daddr,
+					    s->dport,
 					    flags, dest);
 			if (dest)
 				atomic_dec(&dest->refcnt);
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (11 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02 22:28   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions Julius Volz
                   ` (12 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add IPv6 support to IP_VS_XMIT() and to the xmit routing cache, introducing
a new function __ip_vs_get_out_rt_v6().

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 88199c9..7bebd5c 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -20,6 +20,9 @@
 #include <net/udp.h>
 #include <net/icmp.h>                   /* for icmp_send */
 #include <net/route.h>                  /* for ip_route_output */
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <linux/icmpv6.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 
@@ -47,7 +50,8 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
 
 	if (!dst)
 		return NULL;
-	if ((dst->obsolete || rtos != dest->dst_rtos) &&
+	if ((dst->obsolete
+	     || (dest->af == AF_INET && rtos != dest->dst_rtos)) &&
 	    dst->ops->check(dst, cookie) == NULL) {
 		dest->dst_cache = NULL;
 		dst_release(dst);
@@ -109,6 +113,58 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
 	return rt;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static struct rt6_info *
+__ip_vs_get_out_rt_v6(struct ip_vs_conn *cp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	struct ip_vs_dest *dest = cp->dest;
+
+	if (dest) {
+		spin_lock(&dest->dst_lock);
+		if (!(rt = (struct rt6_info *)
+		      __ip_vs_dst_check(dest, 0, 0))) {
+			struct flowi fl = {
+				.oif = 0,
+				.nl_u = {
+					.ip6_u = {
+						.daddr = dest->addr.in6,
+						.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+			};
+
+			if (!(rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl))) {
+				spin_unlock(&dest->dst_lock);
+				IP_VS_DBG_RL("ip6_route_output error, "
+					     "dest: " NIP6_FMT "\n",
+					     NIP6(dest->addr.in6));
+				return NULL;
+			}
+			__ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
+			IP_VS_DBG(10, "new dst " NIP6_FMT ", refcnt=%d\n",
+				  NIP6(dest->addr.in6),
+				  atomic_read(&rt->u.dst.__refcnt));
+		}
+		spin_unlock(&dest->dst_lock);
+	} else {
+		struct flowi fl = {
+			.oif = 0,
+			.nl_u = {
+				.ip6_u = {
+					.daddr = cp->daddr.in6,
+					.saddr = { .s6_addr32 = {0, 0, 0, 0}}, } },
+		};
+
+		if (!(rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl))) {
+			IP_VS_DBG_RL("ip6_route_output error, dest: "
+				     NIP6_FMT "\n", NIP6(cp->daddr.in6));
+			return NULL;
+		}
+	}
+
+	return rt;
+}
+#endif
+
 
 /*
  *	Release dest->dst_cache before a dest is removed
@@ -123,11 +179,11 @@ ip_vs_dst_reset(struct ip_vs_dest *dest)
 	dst_release(old_dst);
 }
 
-#define IP_VS_XMIT(skb, rt)				\
+#define IP_VS_XMIT(pf, skb, rt)				\
 do {							\
 	(skb)->ipvs_property = 1;			\
 	skb_forward_csum(skb);				\
-	NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, (skb), NULL,	\
+	NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL,	\
 		(rt)->u.dst.dev, dst_output);		\
 } while (0)
 
@@ -200,7 +256,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
 
-	IP_VS_XMIT(skb, rt);
+	IP_VS_XMIT(PF_INET, skb, rt);
 
 	LeaveFunction(10);
 	return NF_STOLEN;
@@ -276,7 +332,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
 
-	IP_VS_XMIT(skb, rt);
+	IP_VS_XMIT(PF_INET, skb, rt);
 
 	LeaveFunction(10);
 	return NF_STOLEN;
@@ -467,7 +523,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
 
-	IP_VS_XMIT(skb, rt);
+	IP_VS_XMIT(PF_INET, skb, rt);
 
 	LeaveFunction(10);
 	return NF_STOLEN;
@@ -540,7 +596,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
 
-	IP_VS_XMIT(skb, rt);
+	IP_VS_XMIT(PF_INET, skb, rt);
 
 	rc = NF_STOLEN;
 	goto out;
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (12 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  7:32   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 15/25] IPVS: Extend scheduling functions for IPv6 support Julius Volz
                   ` (11 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add xmit functions for IPv6. Also add the already needed __ip_vs_get_out_rt_v6()
to ip_vs_core.c. Bind the new xmit functions to v6 connections.

Signed-off-by: Julius Volz <juliusv@google.com>

 4 files changed, 462 insertions(+), 2 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7de9eb4..a7eda08 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -855,6 +855,18 @@ extern int ip_vs_icmp_xmit
 (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
 extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
 
+#ifdef CONFIG_IP_VS_IPV6
+extern int ip_vs_bypass_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_nat_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_tunnel_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_dr_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_icmp_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
+#endif
 
 /*
  *	This is a simple mechanism to ignore packets when
@@ -899,7 +911,12 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
 }
 
 extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
-		struct ip_vs_conn *cp, int dir);
+			   struct ip_vs_conn *cp, int dir);
+
+#ifdef CONFIG_IP_VS_IPV6
+extern void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+			      struct ip_vs_conn *cp, int dir);
+#endif
 
 extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
 
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 664b42c..814d416 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -388,6 +388,33 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
 	}
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
+{
+	switch (IP_VS_FWD_METHOD(cp)) {
+	case IP_VS_CONN_F_MASQ:
+		cp->packet_xmit = ip_vs_nat_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_TUNNEL:
+		cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_DROUTE:
+		cp->packet_xmit = ip_vs_dr_xmit_v6;
+		break;
+
+	case IP_VS_CONN_F_LOCALNODE:
+		cp->packet_xmit = ip_vs_null_xmit;
+		break;
+
+	case IP_VS_CONN_F_BYPASS:
+		cp->packet_xmit = ip_vs_bypass_xmit_v6;
+		break;
+	}
+}
+#endif
+
 
 static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
 {
@@ -693,7 +720,12 @@ ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
 	cp->timeout = 3*HZ;
 
 	/* Bind its packet transmitter */
-	ip_vs_bind_xmit(cp);
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ip_vs_bind_xmit_v6(cp);
+	else
+#endif
+		ip_vs_bind_xmit(cp);
 
 	if (unlikely(pp && atomic_read(&pp->appcnt)))
 		ip_vs_bind_app(cp, pp);
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 2d5a433..d6f5bf9 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -570,6 +570,49 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
 			"Forwarding altered incoming ICMP");
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+		    struct ip_vs_conn *cp, int inout)
+{
+	struct ipv6hdr *iph	 = ipv6_hdr(skb);
+	unsigned int icmp_offset = sizeof(struct ipv6hdr);
+	struct icmp6hdr *icmph	 = (struct icmp6hdr *)(skb_network_header(skb) +
+						      icmp_offset);
+	struct ipv6hdr *ciph	 = (struct ipv6hdr *)(icmph + 1);
+
+	if (inout) {
+		iph->saddr = cp->vaddr.in6;
+		ciph->daddr = cp->vaddr.in6;
+	} else {
+		iph->daddr = cp->daddr.in6;
+		ciph->saddr = cp->daddr.in6;
+	}
+
+	/* the TCP/UDP port */
+	if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr) {
+		__be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
+
+		if (inout)
+			ports[1] = cp->vport;
+		else
+			ports[0] = cp->dport;
+	}
+
+	/* And finally the ICMP checksum */
+	icmph->icmp6_cksum = 0;
+	/* TODO IPv6: is this correct for ICMPv6? */
+	ip_vs_checksum_complete(skb, icmp_offset);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	if (inout)
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered outgoing ICMPv6");
+	else
+		IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+			"Forwarding altered incoming ICMPv6");
+}
+#endif
+
 /*
  *	Handle ICMP messages in the inside-to-outside direction (outgoing).
  *	Find any that might be relevant, check against existing connections,
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 7bebd5c..15c59aa 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -269,6 +269,68 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	return NF_STOLEN;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		     struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	struct ipv6hdr  *iph = ipv6_hdr(skb);
+	int    mtu;
+	struct flowi fl = {
+		.oif = 0,
+		.nl_u = {
+			.ip6_u = {
+				.daddr = iph->daddr,
+				.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+	};
+
+	EnterFunction(10);
+
+	if (!(rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl))) {
+		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, "
+			     "dest: " NIP6_FMT "\n", NIP6(iph->daddr));
+		goto tx_error_icmp;
+	}
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+		dst_release(&rt->u.dst);
+		return NF_STOLEN;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+ tx_error_icmp:
+	dst_link_failure(skb);
+ tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
 
 /*
  *      NAT transmitter (only for outside-to-inside nat forwarding)
@@ -348,6 +410,80 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	goto tx_error;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+	          struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;		/* Route to the other host */
+	int mtu;
+
+	EnterFunction(10);
+
+	/* check if it is a connection of no-client-port */
+	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+		__be16 _pt, *p;
+		p = skb_header_pointer(skb, sizeof(struct ipv6hdr), sizeof(_pt), &_pt);
+		if (p == NULL)
+			goto tx_error;
+		ip_vs_conn_fill_cport(cp, *p);
+		IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
+	}
+
+	if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit_v6(): frag needed for");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* mangle the packet */
+	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
+		goto tx_error;
+	ipv6_hdr(skb)->daddr = cp->daddr.in6;
+
+	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+
+	/* FIXME: when application helper enlarges the packet and the length
+	   is larger than the MTU of outgoing device, there will be still
+	   MTU problem. */
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	LeaveFunction(10);
+	kfree_skb(skb);
+	return NF_STOLEN;
+  tx_error_put:
+	dst_release(&rt->u.dst);
+	goto tx_error;
+}
+#endif
+
 
 /*
  *   IP Tunneling transmitter
@@ -479,6 +615,111 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	return NF_STOLEN;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		     struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	struct net_device *tdev;		/* Device to other host */
+	struct ipv6hdr  *old_iph = ipv6_hdr(skb);
+	sk_buff_data_t old_transport_header = skb->transport_header;
+	struct ipv6hdr  *iph;			/* Our new IP header */
+	unsigned int max_headroom;		/* The extra header space needed */
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (skb->protocol != htons(ETH_P_IPV6)) {
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): protocol error, "
+			     "ETH_P_IPV6: %d, skb protocol: %d\n",
+			     htons(ETH_P_IPV6), skb->protocol);
+		goto tx_error;
+	}
+
+	if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+		goto tx_error_icmp;
+
+	tdev = rt->u.dst.dev;
+
+	mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
+	/* TODO IPv6: do we need this check in IPv6? */
+	if (mtu < 1280) {
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n");
+		goto tx_error;
+	}
+	if (skb->dst)
+		skb->dst->ops->update_pmtu(skb->dst, mtu);
+
+	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Okay, now see if we can stuff it in the buffer as-is.
+	 */
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
+
+	if (skb_headroom(skb) < max_headroom
+	    || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb =
+			skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			dst_release(&rt->u.dst);
+			kfree_skb(skb);
+			IP_VS_ERR_RL("ip_vs_tunnel_xmit_v6(): no memory\n");
+			return NF_STOLEN;
+		}
+		kfree_skb(skb);
+		skb = new_skb;
+		old_iph = ipv6_hdr(skb);
+	}
+
+	skb->transport_header = old_transport_header;
+
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/*
+	 *	Push down and install the IPIP header.
+	 */
+	iph			=	ipv6_hdr(skb);
+	iph->version		=	6;
+	iph->nexthdr		=	IPPROTO_IPV6;
+	iph->payload_len	=	old_iph->payload_len + sizeof(old_iph);
+	iph->priority		=	old_iph->priority;
+	memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
+	iph->daddr		=	rt->rt6i_dst.addr;
+	iph->saddr		=	cp->vaddr.in6; /* rt->rt6i_src.addr; */
+	iph->hop_limit		=	old_iph->hop_limit;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	ip6_local_out(skb);
+
+	LeaveFunction(10);
+
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
+
 
 /*
  *      Direct Routing transmitter
@@ -536,6 +777,58 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	return NF_STOLEN;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+	         struct ip_vs_protocol *pp)
+{
+	struct rt6_info *rt;			/* Route to the other host */
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		dst_release(&rt->u.dst);
+		IP_VS_DBG_RL("ip_vs_dr_xmit_v6(): frag needed\n");
+		goto tx_error;
+	}
+
+	/*
+	 * Call ip_send_check because we are not sure it is called
+	 * after ip_defrag. Is copy-on-write needed?
+	 */
+	if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+		dst_release(&rt->u.dst);
+		return NF_STOLEN;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	return NF_STOLEN;
+}
+#endif
+
 
 /*
  *	ICMP packet transmitter
@@ -613,3 +906,78 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	ip_rt_put(rt);
 	goto tx_error;
 }
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+		struct ip_vs_protocol *pp, int offset)
+{
+	struct rt6_info	*rt;	/* Route to the other host */
+	int mtu;
+	int rc;
+
+	EnterFunction(10);
+
+	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
+	   forwarded directly here, because there is no need to
+	   translate address/port back */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+		if (cp->packet_xmit)
+			rc = cp->packet_xmit(skb, cp, pp);
+		else
+			rc = NF_ACCEPT;
+		/* do not touch skb anymore */
+		atomic_inc(&cp->in_pkts);
+		goto out;
+	}
+
+	/*
+	 * mangle and send the packet here (only for VS/NAT)
+	 */
+
+	if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = dst_mtu(&rt->u.dst);
+	if (skb->len > mtu) {
+		dst_release(&rt->u.dst);
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* copy-on-write the packet before mangling it */
+	if (!skb_make_writable(skb, offset))
+		goto tx_error_put;
+
+	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+		goto tx_error_put;
+
+	/* drop the old route when skb is not shared */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	ip_vs_nat_icmp_v6(skb, pp, cp, 0);
+
+	/* Another hack: avoid icmp_send in ip_fragment */
+	skb->local_df = 1;
+
+	IP_VS_XMIT(PF_INET6, skb, rt);
+
+	rc = NF_STOLEN;
+	goto out;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	dev_kfree_skb(skb);
+	rc = NF_STOLEN;
+  out:
+	LeaveFunction(10);
+	return rc;
+  tx_error_put:
+	dst_release(&rt->u.dst);
+	goto tx_error;
+}
+#endif
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 15/25] IPVS: Extend scheduling functions for IPv6 support
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (13 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6 Julius Volz
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Convert ip_vs_schedule() and ip_vs_sched_persist() to support scheduling of
IPv6 connections.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 31 insertions(+), 25 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index d6f5bf9..8bfd7c2 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -176,19 +176,25 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
-	__be16  dport;	 /* destination port to forward */
+	__be16  dport;			/* destination port to forward */
 	union nf_inet_addr snet;	/* source network of the client,
 					   after masking */
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
 	/* Mask saddr with the netmask to adjust template granularity */
-	snet.ip = iph.saddr.ip & svc->netmask;
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask);
+	else
+#endif
+		snet.ip = iph.saddr.ip & svc->netmask;
 
-	IP_VS_DBG(6, "p-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "
-		  "mnet %u.%u.%u.%u\n",
-		  NIPQUAD(iph.saddr.ip), ntohs(ports[0]),
-		  NIPQUAD(iph.daddr.ip), ntohs(ports[1]),
-		  NIPQUAD(snet));
+	IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
+		      "mnet %s\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.saddr), ntohs(ports[0]),
+		      IP_VS_DBG_ADDR(svc->af, &iph.daddr), ntohs(ports[1]),
+		      IP_VS_DBG_ADDR(svc->af, &snet));
 
 	/*
 	 * As far as we know, FTP is a very complicated network protocol, and
@@ -206,10 +212,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	if (ports[1] == svc->port) {
 		/* Check if a template already exists */
 		if (svc->port != FTPPORT)
-			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
 					     &iph.daddr, ports[1]);
 		else
-			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
 					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
@@ -230,7 +236,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 			 * for ftp service.
 			 */
 			if (svc->port != FTPPORT)
-				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
 						    &snet, 0,
 						    &iph.daddr,
 						    ports[1],
@@ -238,7 +244,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			else
-				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
 						    &snet, 0,
 						    &iph.daddr, 0,
 						    &dest->addr, 0,
@@ -265,10 +271,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 				.all = { 0, 0, 0, htonl(svc->fwmark) }
 			};
 
-			ct = ip_vs_ct_in_get(AF_INET, IPPROTO_IP, &snet, 0,
+			ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
 					     &fwmark, 0);
 		} else
-			ct = ip_vs_ct_in_get(AF_INET, iph.protocol, &snet, 0,
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
 					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
@@ -293,14 +299,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 					.all = { 0, 0, 0, htonl(svc->fwmark) }
 				};
 
-				ct = ip_vs_conn_new(AF_INET, IPPROTO_IP,
+				ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
 						    &snet, 0,
 						    &fwmark, 0,
 						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			} else
-				ct = ip_vs_conn_new(AF_INET, iph.protocol,
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
 						    &snet, 0,
 						    &iph.daddr, 0,
 						    &dest->addr, 0,
@@ -320,7 +326,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	/*
 	 *    Create a new connection according to the template
 	 */
-	cp = ip_vs_conn_new(AF_INET, iph.protocol,
+	cp = ip_vs_conn_new(svc->af, iph.protocol,
 			    &iph.saddr, ports[0],
 			    &iph.daddr, ports[1],
 			    &dest->addr, dport,
@@ -387,7 +393,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	/*
 	 *    Create a connection entry.
 	 */
-	cp = ip_vs_conn_new(AF_INET, iph.protocol,
+	cp = ip_vs_conn_new(svc->af, iph.protocol,
 			    &iph.saddr, pptr[0],
 			    &iph.daddr, pptr[1],
 			    &dest->addr, dest->port ? dest->port : pptr[1],
@@ -396,13 +402,13 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 	if (cp == NULL)
 		return NULL;
 
-	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
-		  "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
-		  ip_vs_fwd_tag(cp),
-		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
-		  cp->flags, atomic_read(&cp->refcnt));
+	IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
+		      "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
+		      ip_vs_fwd_tag(cp),
+		      IP_VS_DBG_ADDR(svc->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(svc->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(svc->af, &cp->daddr), ntohs(cp->dport),
+		      cp->flags, atomic_read(&cp->refcnt));
 
 	ip_vs_conn_stats(cp, svc);
 	return cp;
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (14 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 15/25] IPVS: Extend scheduling functions for IPv6 support Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  7:40   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions Julius Volz
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add Netfilter hook functions or modify existing ones, if possible, to
process IPv6 packets. Some support functions are also added/modified for
this. ip_vs_nat_icmp_v6() was already added in the patch that added the v6
xmit functions, as it is called from one of them.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 326 insertions(+), 36 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 8bfd7c2..0bf871c 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -39,6 +39,11 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <linux/netfilter_ipv6.h>
+#endif
+
 #include <net/ip_vs.h>
 
 
@@ -60,6 +65,7 @@ EXPORT_SYMBOL(ip_vs_get_debug_level);
 
 /* ID used in ICMP lookups */
 #define icmp_id(icmph)          (((icmph)->un).echo.id)
+#define icmpv6_id(icmph)        (icmph->icmp6_dataun.u_echo.identifier)
 
 const char *ip_vs_proto_name(unsigned proto)
 {
@@ -74,6 +80,10 @@ const char *ip_vs_proto_name(unsigned proto)
 		return "TCP";
 	case IPPROTO_ICMP:
 		return "ICMP";
+#ifdef CONFIG_IP_VS_IPV6
+	case IPPROTO_ICMPV6:
+		return "ICMPv6";
+#endif
 	default:
 		sprintf(buf, "IP_%d", proto);
 		return buf;
@@ -425,7 +435,8 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 {
 	__be16 _ports[2], *pptr;
 	struct ip_vs_iphdr iph;
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	int unicast;
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
 	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
 	if (pptr == NULL) {
@@ -433,11 +444,17 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 		return NF_DROP;
 	}
 
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		unicast = ipv6_addr_type(&iph.daddr.in6) & IPV6_ADDR_UNICAST;
+	else
+#endif
+		unicast = (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST);
+
 	/* if it is fwmark-based service, the cache_bypass sysctl is up
-	   and the destination is RTN_UNICAST (and not local), then create
+	   and the destination is a non-local unicast, then create
 	   a cache_bypass connection entry */
-	if (sysctl_ip_vs_cache_bypass && svc->fwmark
-	    && (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST)) {
+	if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
 		int ret, cs;
 		struct ip_vs_conn *cp;
 
@@ -445,7 +462,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 
 		/* create a new connection entry */
 		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
-		cp = ip_vs_conn_new(AF_INET, iph.protocol,
+		cp = ip_vs_conn_new(svc->af, iph.protocol,
 				    &iph.saddr, pptr[0],
 				    &iph.daddr, pptr[1],
 				    0, 0,
@@ -489,7 +506,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 	 * created, the TCP RST packet cannot be sent, instead that
 	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
 	 */
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6)
+		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0,
+			    skb->dev);
+	else
+#endif
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
 	return NF_DROP;
 }
 
@@ -528,6 +552,14 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
 	return err;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
+{
+	/* TODO IPv6: Find out what to do here for IPv6 */
+	return 0;
+}
+#endif
+
 /*
  * Packet has been made sufficiently writable in caller
  * - inout: 1=in->out, 0=out->in
@@ -727,11 +759,116 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
 	return verdict;
 }
 
-static inline int is_tcp_reset(const struct sk_buff *skb)
+#ifdef CONFIG_IP_VS_IPV6
+static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
+{
+	struct ipv6hdr *iph;
+	struct icmp6hdr	_icmph, *ic;
+	struct ipv6hdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset, verdict;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
+		if (ip_vs_gather_frags_v6(skb, IP_DEFRAG_VS_OUT))
+			return NF_STOLEN;
+	}
+
+	iph = ipv6_hdr(skb);
+	offset = sizeof(struct ipv6hdr);
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
+		  NIP6(iph->saddr), NIP6(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
+	    (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
+	    (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->nexthdr);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	/* TODO: we don't support fragmentation at the moment anyways */
+	if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMPv6 for");
+
+	offset += sizeof(struct ipv6hdr);
+
+	ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_out_get(AF_INET6, skb, pp, &ciph, offset, 1);
+	if (!cp)
+		return NF_ACCEPT;
+
+	verdict = NF_DROP;
+
+	if (IP_VS_FWD_METHOD(cp) != 0) {
+		IP_VS_ERR("shouldn't reach here, because the box is on the "
+			  "half connection in the tun/dr module.\n");
+	}
+
+	/* Ensure the checksum is correct */
+	if (!skb_csum_unnecessary(skb)
+	    && ip_vs_checksum_complete(skb, sizeof(struct ipv6hdr))) {
+		/* Failed checksum! */
+		IP_VS_DBG(1, "Forward ICMPv6: failed checksum from "
+			  NIP6_FMT "!\n",
+			  NIP6(iph->saddr));
+		goto out;
+	}
+
+	if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
+		offset += 2 * sizeof(__u16);
+	if (!skb_make_writable(skb, offset))
+		goto out;
+
+	ip_vs_nat_icmp_v6(skb, pp, cp, 1);
+
+	/* do the statistics and put it back */
+	ip_vs_out_stats(cp, skb);
+
+	skb->ipvs_property = 1;
+	verdict = NF_ACCEPT;
+
+  out:
+	__ip_vs_conn_put(cp);
+
+	return verdict;
+}
+#endif
+
+static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
 {
 	struct tcphdr _tcph, *th;
 
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, nh_len, sizeof(_tcph), &_tcph);
 	if (th == NULL)
 		return 0;
 	return th->rst;
@@ -750,38 +887,64 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 	struct ip_vs_iphdr iph;
 	struct ip_vs_protocol *pp;
 	struct ip_vs_conn *cp;
+	int af;
 
 	EnterFunction(11);
 
+	af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
+
 	if (skb->ipvs_property)
 		return NF_ACCEPT;
 
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
-	if (unlikely(iph.protocol == IPPROTO_ICMP)) {
-		int related, verdict = ip_vs_out_icmp(skb, &related);
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
+			int related, verdict = ip_vs_out_icmp_v6(skb, &related);
 
-		if (related)
-			return verdict;
-		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
-	}
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+	} else
+#endif
+		if (unlikely(iph.protocol == IPPROTO_ICMP)) {
+			int related, verdict = ip_vs_out_icmp(skb, &related);
+
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
 
 	pp = ip_vs_proto_get(iph.protocol);
 	if (unlikely(!pp))
 		return NF_ACCEPT;
 
 	/* reassemble IP fragments */
-	if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
-		     !pp->dont_defrag)) {
-		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
-			return NF_STOLEN;
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
+			int related, verdict = ip_vs_out_icmp_v6(skb, &related);
 
-		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
-	}
+			if (related)
+				return verdict;
+
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+	} else
+#endif
+		if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
+			     !pp->dont_defrag)) {
+			if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
+				return NF_STOLEN;
+
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
 
 	/*
 	 * Check if the packet belongs to an existing entry
 	 */
-	cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0);
+	cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		if (sysctl_ip_vs_nat_icmp_send &&
@@ -794,16 +957,26 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 			if (pptr == NULL)
 				return NF_ACCEPT;	/* Not for me */
 			if (ip_vs_lookup_real_service(iph.protocol,
-						      iph.saddr.ip, pptr[0])) {
+						      iph.saddr.ip,
+						      pptr[0])) {
 				/*
 				 * Notify the real server: there is no
 				 * existing entry if it is not RST
 				 * packet or not TCP packet.
 				 */
 				if (iph.protocol != IPPROTO_TCP
-				    || !is_tcp_reset(skb)) {
-					icmp_send(skb,ICMP_DEST_UNREACH,
-						  ICMP_PORT_UNREACH, 0);
+				    || !is_tcp_reset(skb, iph.len)) {
+#ifdef CONFIG_IP_VS_IPV6
+					if (af == AF_INET6)
+						icmpv6_send(skb,
+							    ICMPV6_DEST_UNREACH,
+							    ICMPV6_PORT_UNREACH,
+							    0, skb->dev);
+					else
+#endif
+						icmp_send(skb,
+							  ICMP_DEST_UNREACH,
+							  ICMP_PORT_UNREACH, 0);
 					return NF_DROP;
 				}
 			}
@@ -821,8 +994,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 	/* mangle the packet */
 	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
 		goto drop;
-	ip_hdr(skb)->saddr = cp->vaddr.ip;
-	ip_send_check(ip_hdr(skb));
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		ipv6_hdr(skb)->saddr = cp->vaddr.in6;
+	else
+#endif
+	{
+		ip_hdr(skb)->saddr = cp->vaddr.ip;
+		ip_send_check(ip_hdr(skb));
+	}
 
 	/* For policy routing, packets originating from this
 	 * machine itself may be routed differently to packets
@@ -830,8 +1011,14 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 	 * if it came from this machine itself.  So re-compute
 	 * the routing information.
 	 */
-	if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
-		goto drop;
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (ip6_route_me_harder(skb) != 0)
+			goto drop;
+	} else
+#endif
+		if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
+			goto drop;
 
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
 
@@ -949,6 +1136,92 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
 	return verdict;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static int
+ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
+{
+	struct ipv6hdr *iph;
+	struct icmp6hdr	_icmph, *ic;
+	struct ipv6hdr	_ciph, *cih;	/* The ip header contained within the ICMP */
+	struct ip_vs_iphdr ciph;
+	struct ip_vs_conn *cp;
+	struct ip_vs_protocol *pp;
+	unsigned int offset, verdict;
+
+	*related = 1;
+
+	/* reassemble IP fragments */
+	if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
+		if (ip_vs_gather_frags_v6(skb, hooknum == NF_INET_LOCAL_IN ?
+					       IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD))
+			return NF_STOLEN;
+	}
+
+	iph = ipv6_hdr(skb);
+	offset = sizeof(struct ipv6hdr);
+	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
+	if (ic == NULL)
+		return NF_DROP;
+
+	IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
+		  NIP6(iph->saddr), NIP6(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
+	    (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
+	    (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+		*related = 0;
+		return NF_ACCEPT;
+	}
+
+	/* Now find the contained IP header */
+	offset += sizeof(_icmph);
+	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
+	if (cih == NULL)
+		return NF_ACCEPT; /* The packet looks wrong, ignore */
+
+	pp = ip_vs_proto_get(cih->nexthdr);
+	if (!pp)
+		return NF_ACCEPT;
+
+	/* Is the embedded protocol header present? */
+	/* TODO: we don't support fragmentation at the moment anyways */
+	if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
+		return NF_ACCEPT;
+
+	IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMPv6 for");
+
+	offset += sizeof(struct ipv6hdr);
+
+	ip_vs_fill_iphdr(AF_INET6, cih, &ciph);
+	/* The embedded headers contain source and dest in reverse order */
+	cp = pp->conn_in_get(AF_INET6, skb, pp, &ciph, offset, 1);
+	if (!cp)
+		return NF_ACCEPT;
+
+	verdict = NF_DROP;
+
+	/* do the statistics and put it back */
+	ip_vs_in_stats(cp, skb);
+	if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr)
+		offset += 2 * sizeof(__u16);
+	verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
+	/* do not touch skb anymore */
+
+	__ip_vs_conn_put(cp);
+
+	return verdict;
+}
+#endif
+
+
 /*
  *	Check if it's for virtual services, look it up,
  *	and send it on its way...
@@ -961,9 +1234,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 	struct ip_vs_iphdr iph;
 	struct ip_vs_protocol *pp;
 	struct ip_vs_conn *cp;
-	int ret, restart;
+	int ret, restart, af;
+
+	af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
 
-	ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 
 	/*
 	 *	Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@@ -974,7 +1249,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 		IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
 			      skb->pkt_type,
 			      iph.protocol,
-			      IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
+			      IP_VS_DBG_ADDR(af, &iph.daddr));
 		return NF_ACCEPT;
 	}
 
@@ -983,7 +1258,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 
 		if (related)
 			return verdict;
-		ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+		ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 	}
 
 	/* Protocol supported? */
@@ -994,12 +1269,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 	/*
 	 * Check if the packet belongs to an existing connection entry
 	 */
-	cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0);
+	cp = pp->conn_in_get(af, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		int v;
 
-		if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
+		if (!pp->conn_schedule(af, skb, pp, &v, &cp))
 			return v;
 	}
 
@@ -1082,6 +1357,21 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
 	return ip_vs_in_icmp(skb, &r, hooknum);
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static unsigned int
+ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
+		      const struct net_device *in, const struct net_device *out,
+		      int (*okfn)(struct sk_buff *))
+{
+	int r;
+
+	if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
+		return NF_ACCEPT;
+
+	return ip_vs_in_icmp_v6(skb, &r, hooknum);
+}
+#endif
+
 
 static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 	/* After packet filtering, forward packet through VS/DR, VS/TUN,
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (15 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6 Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  7:46   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output Julius Volz
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Convert functions for looking up destinations (real servers) to support
IPv6 services/dests.

Signed-off-by: Julius Volz <juliusv@google.com>

 5 files changed, 66 insertions(+), 37 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index a7eda08..c163c18 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -804,14 +804,16 @@ static inline void ip_vs_service_put(struct ip_vs_service *svc)
 }
 
 extern struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
+ip_vs_lookup_real_service(int af, __u16 protocol,
+			  const union nf_inet_addr *daddr, __be16 dport);
+
 extern int ip_vs_use_count_inc(void);
 extern void ip_vs_use_count_dec(void);
 extern int ip_vs_control_init(void);
 extern void ip_vs_control_cleanup(void);
 extern struct ip_vs_dest *
-ip_vs_find_dest(__be32 daddr, __be16 dport,
-		 __be32 vaddr, __be16 vport, __u16 protocol);
+ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport,
+		const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol);
 extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
 
 
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 814d416..2f5c4d8 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -490,8 +490,9 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
 	struct ip_vs_dest *dest;
 
 	if ((cp) && (!cp->dest)) {
-		dest = ip_vs_find_dest(cp->daddr.ip, cp->dport,
-				       cp->vaddr.ip, cp->vport, cp->protocol);
+		dest = ip_vs_find_dest(cp->af, &cp->daddr, cp->dport,
+				       &cp->vaddr, cp->vport,
+				       cp->protocol);
 		ip_vs_bind_dest(cp, dest);
 		return dest;
 	} else
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 0bf871c..2725b93 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -956,8 +956,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
 						  sizeof(_ports), _ports);
 			if (pptr == NULL)
 				return NF_ACCEPT;	/* Not for me */
-			if (ip_vs_lookup_real_service(iph.protocol,
-						      iph.saddr.ip,
+			if (ip_vs_lookup_real_service(af, iph.protocol,
+						      &iph.saddr,
 						      pptr[0])) {
 				/*
 				 * Notify the real server: there is no
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 151d368..3dae1d9 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -492,11 +492,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
 /*
  *	Returns hash value for real service
  */
-static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
+static __inline__ unsigned ip_vs_rs_hashkey(int af,
+					    const union nf_inet_addr *addr,
+					    __be16 port)
 {
 	register unsigned porth = ntohs(port);
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
 
-	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
+	return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
 		& IP_VS_RTAB_MASK;
 }
 
@@ -516,7 +525,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
 	 *	Hash by proto,addr,port,
 	 *	which are the parameters of the real service.
 	 */
-	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
+	hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
+
 	list_add(&dest->d_list, &ip_vs_rtable[hash]);
 
 	return 1;
@@ -543,7 +553,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
  *	Lookup real service by <proto,addr,port> in the real service table.
  */
 struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
+ip_vs_lookup_real_service(int af, __u16 protocol,
+			  const union nf_inet_addr *daddr,
+			  __be16 dport)
 {
 	unsigned hash;
 	struct ip_vs_dest *dest;
@@ -552,11 +564,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
 	 *	Check for "full" addressed entries
 	 *	Return the first found entry
 	 */
-	hash = ip_vs_rs_hashkey(daddr, dport);
+	hash = ip_vs_rs_hashkey(af, daddr, dport);
 
 	read_lock(&__ip_vs_rs_lock);
 	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
-		if ((dest->addr.ip == daddr)
+		if ((dest->af == af)
+		    && ip_vs_addr_equal(af, &dest->addr, daddr)
 		    && (dest->port == dport)
 		    && ((dest->protocol == protocol) ||
 			dest->vfwmark)) {
@@ -574,7 +587,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
  *	Lookup destination by {addr,port} in the given service
  */
 static struct ip_vs_dest *
-ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+		  __be16 dport)
 {
 	struct ip_vs_dest *dest;
 
@@ -582,7 +596,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 	 * Find the destination for the given service
 	 */
 	list_for_each_entry(dest, &svc->destinations, n_list) {
-		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
+		if ((dest->af == svc->af)
+		    && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
+		    && (dest->port == dport)) {
 			/* HIT */
 			return dest;
 		}
@@ -601,14 +617,14 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
  * ip_vs_lookup_real_service() looked promissing, but
  * seems not working as expected.
  */
-struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
-				    __be32 vaddr, __be16 vport, __u16 protocol)
+struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
+				   __be16 dport, const union nf_inet_addr *vaddr,
+				   __be16 vport, __u16 protocol)
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_service *svc;
-	union nf_inet_addr _vaddr = { .ip = vaddr };
 
-	svc = ip_vs_service_get(AF_INET, 0, protocol, &_vaddr, vport);
+	svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
 	if (!svc)
 		return NULL;
 	dest = ip_vs_lookup_dest(svc, daddr, dport);
@@ -629,7 +645,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
  *  scheduling.
  */
 static struct ip_vs_dest *
-ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+		     __be16 dport)
 {
 	struct ip_vs_dest *dest, *nxt;
 
@@ -637,17 +654,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 	 * Find the destination in trash
 	 */
 	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
-		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
-			  "dest->refcnt=%d\n",
-			  dest->vfwmark,
-			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
-			  atomic_read(&dest->refcnt));
-		if (dest->addr.ip == daddr &&
+		IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
+			      "dest->refcnt=%d\n",
+			      dest->vfwmark,
+			      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+			      ntohs(dest->port),
+			      atomic_read(&dest->refcnt));
+		if (dest->af == svc->af &&
+		    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
 		    dest->port == dport &&
 		    dest->vfwmark == svc->fwmark &&
 		    dest->protocol == svc->protocol &&
 		    (svc->fwmark ||
-		     (dest->vaddr.ip == svc->addr.ip &&
+		     (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
 		      dest->vport == svc->port))) {
 			/* HIT */
 			return dest;
@@ -657,10 +676,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 		 * Try to purge the destination from trash if not referenced
 		 */
 		if (atomic_read(&dest->refcnt) == 1) {
-			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
-				  "from trash\n",
-				  dest->vfwmark,
-				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
+			IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
+				      "from trash\n",
+				      dest->vfwmark,
+				      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+				      ntohs(dest->port));
 			list_del(&dest->n_list);
 			ip_vs_dst_reset(dest);
 			__ip_vs_unbind_svc(dest);
@@ -847,7 +867,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 	/*
 	 * Check if the dest already exists in the list
 	 */
-	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
+	dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
 	if (dest != NULL) {
 		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
 		return -EEXIST;
@@ -857,7 +878,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 	 * Check if the dest already exists in the trash and
 	 * is from the same service
 	 */
-	dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
+	dest = ip_vs_trash_get_dest(svc, &daddr, dport);
+
 	if (dest != NULL) {
 		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
 			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
@@ -956,7 +978,8 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 	/*
 	 *  Lookup the destination list
 	 */
-	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
+	dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
 		return -ENOENT;
@@ -1054,7 +1077,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 
 	EnterFunction(2);
 
-	dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
+	dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
 
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 3ce1093..40647ed 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -383,8 +383,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 			 * If it is not found the connection will remain unbound
 			 * but still handled.
 			 */
-			dest = ip_vs_find_dest(s->daddr, s->dport,
-					       s->vaddr, s->vport,
+			dest = ip_vs_find_dest(AF_INET,
+					       (union nf_inet_addr *)&s->daddr,
+					       s->dport,
+					       (union nf_inet_addr *)&s->vaddr,
+					       s->vport,
 					       s->protocol);
 			/*  Set the approprite ativity flag */
 			if (s->protocol == IPPROTO_TCP) {
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (16 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  7:49   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 19/25] IVPS: Disable sync daemon for IPv6 connections Julius Volz
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam

From: Vince Busam <vbusam@google.com>

Correctly output IPv6 connection/service/dest entries in procfs files.

Signed-off-by: Vince Busam <vbusam@google.com>

 2 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 2f5c4d8..7f33171 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -814,8 +814,20 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
 	else {
 		const struct ip_vs_conn *cp = v;
 
-		seq_printf(seq,
-			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			seq_printf(seq,
+				"%-3s " NIP6_FMT " %04X " NIP6_FMT " %04X " NIP6_FMT " %04X %-11s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				NIP6(cp->caddr.in6), ntohs(cp->cport),
+				NIP6(cp->vaddr.in6), ntohs(cp->vport),
+				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				(cp->timer.expires-jiffies)/HZ);
+		else
+#endif
+			seq_printf(seq,
+				"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
 				ntohl(cp->caddr.ip), ntohs(cp->cport),
 				ntohl(cp->vaddr.ip), ntohs(cp->vport),
@@ -863,8 +875,23 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
 	else {
 		const struct ip_vs_conn *cp = v;
 
-		seq_printf(seq,
-			"%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
+#ifdef CONFIG_IP_VS_IPV6
+		if (cp->af == AF_INET6)
+			seq_printf(seq,
+				"%-3s " NIP6_FMT " %04X " NIP6_FMT
+				" %04X " NIP6_FMT " %04X %-11s %-6s %7lu\n",
+				ip_vs_proto_name(cp->protocol),
+				NIP6(cp->caddr.in6), ntohs(cp->cport),
+				NIP6(cp->vaddr.in6), ntohs(cp->vport),
+				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				ip_vs_state_name(cp->protocol, cp->state),
+				ip_vs_origin_name(cp->flags),
+				(cp->timer.expires-jiffies)/HZ);
+		else
+#endif
+			seq_printf(seq,
+				"%-3s %08X %04X %08X %04X "
+				"%08X %04X %-11s %-6s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
 				ntohl(cp->caddr.ip), ntohs(cp->cport),
 				ntohl(cp->vaddr.ip), ntohs(cp->vport),
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 3dae1d9..fe17504 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1792,15 +1792,25 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
 		const struct ip_vs_iter *iter = seq->private;
 		const struct ip_vs_dest *dest;
 
-		if (iter->table == ip_vs_svc_table)
-			seq_printf(seq, "%s  %08X:%04X %s ",
-				   ip_vs_proto_name(svc->protocol),
-				   ntohl(svc->addr.ip),
-				   ntohs(svc->port),
-				   svc->scheduler->name);
-		else
+		if (iter->table == ip_vs_svc_table) {
+#ifdef CONFIG_IP_VS_IPV6
+			if (svc->af == AF_INET6)
+				seq_printf(seq, "%s  [" NIP6_FMT "]:%04X %s ",
+					   ip_vs_proto_name(svc->protocol),
+					   NIP6(svc->addr.in6),
+					   ntohs(svc->port),
+					   svc->scheduler->name);
+			else
+#endif
+				seq_printf(seq, "%s  %08X:%04X %s ",
+					   ip_vs_proto_name(svc->protocol),
+					   ntohl(svc->addr.ip),
+					   ntohs(svc->port),
+					   svc->scheduler->name);
+		} else {
 			seq_printf(seq, "FWM  %08X %s ",
 				   svc->fwmark, svc->scheduler->name);
+		}
 
 		if (svc->flags & IP_VS_SVC_F_PERSISTENT)
 			seq_printf(seq, "persistent %d %08X\n",
@@ -1810,13 +1820,27 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
 			seq_putc(seq, '\n');
 
 		list_for_each_entry(dest, &svc->destinations, n_list) {
-			seq_printf(seq,
-				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
-				   ntohl(dest->addr.ip), ntohs(dest->port),
-				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
-				   atomic_read(&dest->weight),
-				   atomic_read(&dest->activeconns),
-				   atomic_read(&dest->inactconns));
+#ifdef CONFIG_IP_VS_IPV6
+			if (dest->af == AF_INET6)
+				seq_printf(seq,
+					   "  -> [" NIP6_FMT "]:%04X"
+					   "      %-7s %-6d %-10d %-10d\n",
+					   NIP6(dest->addr.in6), ntohs(dest->port),
+					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					   atomic_read(&dest->weight),
+					   atomic_read(&dest->activeconns),
+					   atomic_read(&dest->inactconns));
+			else
+#endif
+				seq_printf(seq,
+					   "  -> %08X:%04X      "
+					   "%-7s %-6d %-10d %-10d\n",
+					   ntohl(dest->addr.ip), ntohs(dest->port),
+					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					   atomic_read(&dest->weight),
+					   atomic_read(&dest->activeconns),
+					   atomic_read(&dest->inactconns));
+
 		}
 	}
 	return 0;
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 19/25] IVPS: Disable sync daemon for IPv6 connections
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (17 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 20/25] IPVS: Turn off FTP application helper for IPv6 Julius Volz
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Disable the sync daemon for IPv6 connections, works only with IPv4 for now.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 2725b93..141454d 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -1318,7 +1318,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 	 * encorage the standby servers to update the connections timeout
 	 */
 	atomic_inc(&cp->in_pkts);
-	if ((ip_vs_sync_state & IP_VS_STATE_MASTER) &&
+	if (af == AF_INET &&
+	    (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
 	    (((cp->protocol != IPPROTO_TCP ||
 	       cp->state == IP_VS_TCP_S_ESTABLISHED) &&
 	      (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 20/25] IPVS: Turn off FTP application helper for IPv6
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (18 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 19/25] IVPS: Disable sync daemon for IPv6 connections Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local Julius Volz
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Immediately return from FTP application helper and do nothing when dealing
with IPv6 packets. IPv6 is not supported by this helper yet.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index c56b2bd..2abc34a 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -147,6 +147,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	unsigned buf_len;
 	int ret;
 
+#ifdef CONFIG_IP_VS_IPV6
+	/* This application helper doesn't work with IPv6 yet,
+	 * so turn this into a no-op for IPv6 packets
+	 */
+	if (cp->af == AF_INET6)
+		return 1;
+#endif
+
 	*diff = 0;
 
 	/* Only useful for established sessions */
@@ -247,6 +255,14 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
 	__be16 port;
 	struct ip_vs_conn *n_cp;
 
+#ifdef CONFIG_IP_VS_IPV6
+	/* This application helper doesn't work with IPv6 yet,
+	 * so turn this into a no-op for IPv6 packets
+	 */
+	if (cp->af == AF_INET6)
+		return 1;
+#endif
+
 	/* no diff required for incoming packets */
 	*diff = 0;
 
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (19 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 20/25] IPVS: Turn off FTP application helper for IPv6 Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  7:57   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros Julius Volz
                   ` (4 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam

From: Vince Busam <vbusam@google.com>

Add __ip_vs_addr_is_local_v6() to find out if an IPv6 address belongs to a
local interface. Use this function to decide whether to set the
IP_VS_CONN_F_LOCALNODE flag for IPv6 destinations.

Signed-off-by: Vince Busam <vbusam@google.com>

 1 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index fe17504..3ce2873 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -35,6 +35,10 @@
 
 #include <net/net_namespace.h>
 #include <net/ip.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#endif
 #include <net/route.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
@@ -91,6 +95,23 @@ int ip_vs_get_debug_level(void)
 }
 #endif
 
+#ifdef CONFIG_IP_VS_IPV6
+/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
+static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) {
+	struct rt6_info *rt;
+	struct flowi fl = {
+		.oif = 0,
+		.nl_u = {
+			.ip6_u = {
+				.daddr = *addr,
+				.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+	};
+	if ((rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl)))
+		if (rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK))
+			return 1;
+	return 0;
+}
+#endif
 /*
  *	update_defense_level is called from keventd and from sysctl,
  *	so it needs to protect itself from softirqs
@@ -750,10 +771,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
 	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
 
 	/* check if local node and update the flags */
-	if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
-		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
-			| IP_VS_CONN_F_LOCALNODE;
-	}
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6) {
+		if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
+			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+				| IP_VS_CONN_F_LOCALNODE;
+		}
+	} else
+#endif
+		if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
+			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+				| IP_VS_CONN_F_LOCALNODE;
+		}
 
 	/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
 	if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
@@ -802,9 +831,19 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
 
 	EnterFunction(2);
 
-	atype = inet_addr_type(&init_net, udest->addr.ip);
-	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
-		return -EINVAL;
+#ifdef CONFIG_IP_VS_IPV6
+	if (svc->af == AF_INET6) {
+		atype = ipv6_addr_type(&udest->addr.in6);
+		if (!(atype & IPV6_ADDR_UNICAST) &&
+			!__ip_vs_addr_is_local_v6(&udest->addr.in6))
+			return -EINVAL;
+	} else
+#endif
+	{
+		atype = inet_addr_type(&init_net, udest->addr.ip);
+		if (atype != RTN_LOCAL && atype != RTN_UNICAST)
+			return -EINVAL;
+	}
 
 	dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
 	if (dest == NULL) {
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (20 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  8:00   ` Simon Horman
  2008-09-01 12:56 ` [PATCHv2 RFC 23/25] IPVS: Activate IPv6 Netfilter hooks Julius Volz
                   ` (3 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Adjust various debug outputs to use the new *_BUF macro variants for
correct output of v4/v6 addresses.

Signed-off-by: Julius Volz <juliusv@google.com>

 5 files changed, 110 insertions(+), 83 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index c163c18..fbead05 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -680,24 +680,32 @@ static inline void ip_vs_control_del(struct ip_vs_conn *cp)
 {
 	struct ip_vs_conn *ctl_cp = cp->control;
 	if (!ctl_cp) {
-		IP_VS_ERR("request control DEL for uncontrolled: "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("request control DEL for uncontrolled: "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		return;
 	}
 
-	IP_VS_DBG(7, "DELeting control for: "
-		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
-		  NIPQUAD(cp->caddr),ntohs(cp->cport),
-		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+	IP_VS_DBG_BUF(7, "DELeting control for: "
+		      "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+		      ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
+		      ntohs(ctl_cp->cport));
 
 	cp->control = NULL;
 	if (atomic_read(&ctl_cp->n_control) == 0) {
-		IP_VS_ERR("BUG control DEL with n=0 : "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("BUG control DEL with n=0 : "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		return;
 	}
 	atomic_dec(&ctl_cp->n_control);
@@ -707,17 +715,22 @@ static inline void
 ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
 {
 	if (cp->control) {
-		IP_VS_ERR("request control ADD for already controlled: "
-			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
-			  NIPQUAD(cp->caddr),ntohs(cp->cport),
-			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		IP_VS_ERR_BUF("request control ADD for already controlled: "
+			      "%s:%d to %s:%d\n",
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+			      ntohs(cp->vport));
+
 		ip_vs_control_del(cp);
 	}
 
-	IP_VS_DBG(7, "ADDing control for: "
-		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
-		  NIPQUAD(cp->caddr),ntohs(cp->cport),
-		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+	IP_VS_DBG_BUF(7, "ADDing control for: "
+		      "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+		      ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
+		      ntohs(ctl_cp->cport));
 
 	cp->control = ctl_cp;
 	atomic_inc(&ctl_cp->n_control);
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 7f33171..ffd2fd5 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -448,16 +448,16 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
 		cp->flags |= atomic_read(&dest->conn_flags);
 	cp->dest = dest;
 
-	IP_VS_DBG(7, "Bind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
-		  "dest->refcnt:%d\n",
-		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
-		  ip_vs_fwd_tag(cp), cp->state,
-		  cp->flags, atomic_read(&cp->refcnt),
-		  atomic_read(&dest->refcnt));
+	IP_VS_DBG_BUF(7, "Bind-dest %s c:%s:%d v:%s:%d "
+		      "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
+		      "dest->refcnt:%d\n",
+		      ip_vs_proto_name(cp->protocol),
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
+		      ip_vs_fwd_tag(cp), cp->state,
+		      cp->flags, atomic_read(&cp->refcnt),
+		      atomic_read(&dest->refcnt));
 
 	/* Update the connection counters */
 	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -511,16 +511,16 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
 	if (!dest)
 		return;
 
-	IP_VS_DBG(7, "Unbind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
-		  "dest->refcnt:%d\n",
-		  ip_vs_proto_name(cp->protocol),
-		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
-		  ip_vs_fwd_tag(cp), cp->state,
-		  cp->flags, atomic_read(&cp->refcnt),
-		  atomic_read(&dest->refcnt));
+	IP_VS_DBG_BUF(7, "Unbind-dest %s c:%s:%d v:%s:%d "
+		      "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
+		      "dest->refcnt:%d\n",
+		      ip_vs_proto_name(cp->protocol),
+		      IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
+		      IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
+		      ip_vs_fwd_tag(cp), cp->state,
+		      cp->flags, atomic_read(&cp->refcnt),
+		      atomic_read(&dest->refcnt));
 
 	/* Update the connection counters */
 	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -573,13 +573,16 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
 	    !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
 	    (sysctl_ip_vs_expire_quiescent_template &&
 	     (atomic_read(&dest->weight) == 0))) {
-		IP_VS_DBG(9, "check_template: dest not available for "
-			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
-			  "-> d:%u.%u.%u.%u:%d\n",
-			  ip_vs_proto_name(ct->protocol),
-			  NIPQUAD(ct->caddr.ip), ntohs(ct->cport),
-			  NIPQUAD(ct->vaddr.ip), ntohs(ct->vport),
-			  NIPQUAD(ct->daddr.ip), ntohs(ct->dport));
+		IP_VS_DBG_BUF(9, "check_template: dest not available for "
+			      "protocol %s s:%s:%d v:%s:%d "
+			      "-> d:%s:%d\n",
+			      ip_vs_proto_name(ct->protocol),
+			      IP_VS_DBG_ADDR(ct->af, &ct->caddr),
+			      ntohs(ct->cport),
+			      IP_VS_DBG_ADDR(ct->af, &ct->vaddr),
+			      ntohs(ct->vport),
+			      IP_VS_DBG_ADDR(ct->af, &ct->daddr),
+			      ntohs(ct->dport));
 
 		/*
 		 * Invalidate the connection template
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 3ce2873..e5873c6 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -920,13 +920,14 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 	dest = ip_vs_trash_get_dest(svc, &daddr, dport);
 
 	if (dest != NULL) {
-		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
-			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
-			  NIPQUAD(daddr), ntohs(dport),
-			  atomic_read(&dest->refcnt),
-			  dest->vfwmark,
-			  NIPQUAD(dest->vaddr.ip),
-			  ntohs(dest->vport));
+		IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
+			      "dest->refcnt=%d, service %u/%s:%u\n",
+			      IP_VS_DBG_ADDR(svc->af, &daddr), ntohs(dport),
+			      atomic_read(&dest->refcnt),
+			      dest->vfwmark,
+			      IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
+			      ntohs(dest->vport));
+
 		__ip_vs_update_dest(svc, dest, udest);
 
 		/*
@@ -1072,10 +1073,11 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
 		atomic_dec(&dest->svc->refcnt);
 		kfree(dest);
 	} else {
-		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
-			  "dest->refcnt=%d\n",
-			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
-			  atomic_read(&dest->refcnt));
+		IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, "
+			      "dest->refcnt=%d\n",
+			      IP_VS_DBG_ADDR(dest->af, &dest->addr),
+			      ntohs(dest->port),
+			      atomic_read(&dest->refcnt));
 		list_add(&dest->n_list, &ip_vs_dest_trash);
 		atomic_inc(&dest->refcnt);
 	}
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 3da2bb0..32c0706 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -490,19 +490,22 @@ set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
 	if (new_state != cp->state) {
 		struct ip_vs_dest *dest = cp->dest;
 
-		IP_VS_DBG(8, "%s %s [%c%c%c%c] %u.%u.%u.%u:%d->"
-			  "%u.%u.%u.%u:%d state: %s->%s conn->refcnt:%d\n",
-			  pp->name,
-			  (state_off==TCP_DIR_OUTPUT)?"output ":"input ",
-			  th->syn? 'S' : '.',
-			  th->fin? 'F' : '.',
-			  th->ack? 'A' : '.',
-			  th->rst? 'R' : '.',
-			  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
-			  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-			  tcp_state_name(cp->state),
-			  tcp_state_name(new_state),
-			  atomic_read(&cp->refcnt));
+		IP_VS_DBG_BUF(8, "%s %s [%c%c%c%c] %s:%d->"
+			      "%s:%d state: %s->%s conn->refcnt:%d\n",
+			      pp->name,
+			      (state_off==TCP_DIR_OUTPUT)?"output ":"input ",
+			      th->syn? 'S' : '.',
+			      th->fin? 'F' : '.',
+			      th->ack? 'A' : '.',
+			      th->rst? 'R' : '.',
+			      IP_VS_DBG_ADDR(cp->af, &cp->daddr),
+			      ntohs(cp->dport),
+			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+			      ntohs(cp->cport),
+			      tcp_state_name(cp->state),
+			      tcp_state_name(new_state),
+			      atomic_read(&cp->refcnt));
+
 		if (dest) {
 			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
 			    (new_state != IP_VS_TCP_S_ESTABLISHED)) {
@@ -623,12 +626,15 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
 				break;
 			spin_unlock(&tcp_app_lock);
 
-			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
-				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __func__,
-				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-				  inc->name, ntohs(inc->port));
+			IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
+				      "%s:%u to app %s on port %u\n",
+				      __func__,
+				      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+				      ntohs(cp->cport),
+				      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+				      ntohs(cp->vport),
+				      inc->name, ntohs(inc->port));
+
 			cp->app = inc;
 			if (inc->init_conn)
 				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 0b0b625..9b9f3b3 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -407,12 +407,15 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
 				break;
 			spin_unlock(&udp_app_lock);
 
-			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
-				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __func__,
-				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-				  inc->name, ntohs(inc->port));
+			IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
+				      "%s:%u to app %s on port %u\n",
+				      __func__,
+				      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+				      ntohs(cp->cport),
+				      IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+				      ntohs(cp->vport),
+				      inc->name, ntohs(inc->port));
+
 			cp->app = inc;
 			if (inc->init_conn)
 				result = inc->init_conn(inc, cp);
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 23/25] IPVS: Activate IPv6 Netfilter hooks
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (21 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 24/25] IPVS: Allow adding IPv6 services from userspace Julius Volz
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Register the previously defined or adapted netfilter hook functions for
IPv6 as PF_INET6 hooks.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 141454d..6f5d534 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -1410,6 +1410,43 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 		.hooknum        = NF_INET_POST_ROUTING,
 		.priority       = NF_IP_PRI_NAT_SRC-1,
 	},
+#ifdef CONFIG_IP_VS_IPV6
+	/* After packet filtering, forward packet through VS/DR, VS/TUN,
+	 * or VS/NAT(change destination), so that filtering rules can be
+	 * applied to IPVS. */
+	{
+		.hook		= ip_vs_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_LOCAL_IN,
+		.priority       = 100,
+	},
+	/* After packet filtering, change source only for VS/NAT */
+	{
+		.hook		= ip_vs_out,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 100,
+	},
+	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
+	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
+	{
+		.hook		= ip_vs_forward_icmp_v6,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = 99,
+	},
+	/* Before the netfilter connection tracking, exit from POST_ROUTING */
+	{
+		.hook		= ip_vs_post_routing,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum        = NF_INET_POST_ROUTING,
+		.priority       = NF_IP6_PRI_NAT_SRC-1,
+	},
+#endif
 };
 
 
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 24/25] IPVS: Allow adding IPv6 services from userspace
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (22 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 23/25] IPVS: Activate IPv6 Netfilter hooks Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-01 12:56 ` [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments Julius Volz
  2008-09-02  8:18 ` [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Simon Horman
  25 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Allow adding IPv6 services through the genetlink interface and add checks
to see if the chosen scheduler is supported with IPv6 and whether the
supplied prefix length is sane. Make sure the service count exported via
the sockopt interface only counts IPv4 services.

Signed-off-by: Julius Volz <juliusv@google.com>

 1 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index e5873c6..074efb8 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1173,6 +1173,19 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
 		goto out_mod_dec;
 	}
 
+#ifdef CONFIG_IP_VS_IPV6
+	if (u->af == AF_INET6) {
+		if (!sched->supports_ipv6) {
+			ret = -EAFNOSUPPORT;
+			goto out_err;
+		}
+		if ((u->netmask < 1) || (u->netmask > 128)) {
+			ret = -EINVAL;
+			goto out_err;
+		}
+	}
+#endif
+
 	svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
 	if (svc == NULL) {
 		IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
@@ -1210,7 +1223,10 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
 		atomic_inc(&ip_vs_nullsvc_counter);
 
 	ip_vs_new_estimator(&svc->stats);
-	ip_vs_num_services++;
+
+	/* Count only IPv4 services for old get/setsockopt interface */
+	if (svc->af == AF_INET)
+		ip_vs_num_services++;
 
 	/* Hash the service into the service table */
 	write_lock_bh(&__ip_vs_svc_lock);
@@ -1261,6 +1277,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 	}
 	old_sched = sched;
 
+#ifdef CONFIG_IP_VS_IPV6
+	if (u->af == AF_INET6) {
+		if (!sched->supports_ipv6) {
+			ret = EAFNOSUPPORT;
+			goto out;
+		}
+		if ((u->netmask < 1) || (u->netmask > 128)) {
+			ret = EINVAL;
+			goto out;
+		}
+	}
+#endif
+
 	write_lock_bh(&__ip_vs_svc_lock);
 
 	/*
@@ -1325,7 +1354,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
 	struct ip_vs_dest *dest, *nxt;
 	struct ip_vs_scheduler *old_sched;
 
-	ip_vs_num_services--;
+	/* Count only IPv4 services for old get/setsockopt interface */
+	if (svc->af == AF_INET)
+		ip_vs_num_services--;
+
 	ip_vs_kill_estimator(&svc->stats);
 
 	/* Unbind scheduler */
@@ -2206,6 +2238,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
 
 	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
 		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+			/* Only expose IPv4 entries to old interface */
+			if (svc->af != AF_INET)
+				continue;
+
 			if (count >= get->num_services)
 				goto out;
 			memset(&entry, 0, sizeof(entry));
@@ -2221,6 +2257,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
 
 	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
 		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+			/* Only expose IPv4 entries to old interface */
+			if (svc->af != AF_INET)
+				continue;
+
 			if (count >= get->num_services)
 				goto out;
 			memset(&entry, 0, sizeof(entry));
@@ -2578,7 +2618,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
 	if (!nl_service)
 		return -EMSGSIZE;
 
-	NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET);
+	NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
 
 	if (svc->fwmark) {
 		NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
@@ -2685,8 +2725,11 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
 		return -EINVAL;
 
 	usvc->af = nla_get_u16(nla_af);
-	/* For now, only support IPv4 */
-	if (nla_get_u16(nla_af) != AF_INET)
+#ifdef CONFIG_IP_VS_IPV6
+	if (usvc->af != AF_INET && usvc->af != AF_INET6)
+#else
+	if (usvc->af != AF_INET)
+#endif
 		return -EAFNOSUPPORT;
 
 	if (nla_fwmark) {
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (23 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 24/25] IPVS: Allow adding IPv6 services from userspace Julius Volz
@ 2008-09-01 12:56 ` Julius Volz
  2008-09-02  2:25   ` Stephen Hemminger
  2008-09-02  8:18 ` [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Simon Horman
  25 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-01 12:56 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add notes about the IPv6 changes to the relevant files' header comments.

Signed-off-by: Julius Volz <juliusv@google.com>

 7 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index ffd2fd5..0551145 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -19,6 +19,7 @@
  * and others. Many code here is taken from IP MASQ code of kernel 2.2.
  *
  * Changes:
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 6f5d534..ea00ae7 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -21,6 +21,7 @@
  * Changes:
  *	Paul `Rusty' Russell		properly handle non-linear skbs
  *	Harald Welte			don't use nfcache
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 074efb8..9178ed7 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -15,6 +15,8 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ *	Julius Volz			add Generic Netlink interface
+ * 	Julius Volz, Vince Busam	add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 50f6215..edb80e9 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -10,6 +10,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 32c0706..7d9d2cb 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -10,6 +10,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 9b9f3b3..9278c0d 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -10,6 +10,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 15c59aa..e1a3fde 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -10,6 +10,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ * 	Julius Volz			add first IPv6 support
  *
  */
 
-- 
1.5.4.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments
  2008-09-01 12:56 ` [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments Julius Volz
@ 2008-09-02  2:25   ` Stephen Hemminger
  2008-09-02  9:22     ` Julius Volz
  0 siblings, 1 reply; 46+ messages in thread
From: Stephen Hemminger @ 2008-09-02  2:25 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, horms, kaber, vbusam, Julius Volz

On Mon,  1 Sep 2008 14:56:22 +0200
Julius Volz <juliusv@google.com> wrote:

> Add notes about the IPv6 changes to the relevant files' header comments.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>

No. This is no longer necessary.
Git changelog is sufficient

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses
  2008-09-01 12:55 ` [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
@ 2008-09-02  5:23   ` Simon Horman
  2008-09-02  5:53     ` Simon Horman
  2008-09-02  6:08   ` Simon Horman
  1 sibling, 1 reply; 46+ messages in thread
From: Simon Horman @ 2008-09-02  5:23 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:55:59PM +0200, Julius Volz wrote:
> Introduce new 'af' fields into IPVS data structures for specifying an
> entry's address family. Convert IP addresses to be of type union
> nf_inet_addr.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>
> 
>  19 files changed, 118 insertions(+), 112 deletions(-)
> 
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index a25ad24..01cabd6 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -21,6 +21,9 @@
>  #include <linux/timer.h>
>  
>  #include <net/checksum.h>
> +#include <linux/netfilter.h>		/* for union nf_inet_addr */
> +#include <linux/ipv6.h>			/* for struct ipv6hdr */
> +#include <net/ipv6.h>			/* for ipv6_addr_copy */
>  
>  #ifdef CONFIG_IP_VS_DEBUG
>  #include <linux/net.h>
> @@ -259,9 +262,10 @@ struct ip_vs_conn {
>  	struct list_head        c_list;         /* hashed list heads */
>  
>  	/* Protocol, addresses and port numbers */
> -	__be32                   caddr;          /* client address */
> -	__be32                   vaddr;          /* virtual address */
> -	__be32                   daddr;          /* destination address */
> +	u_int16_t               af;		/* address family */


I believe that the prefered style is to use __u16 for internal
kernel structures, u16 for structures exported to userspace
and not u_int16_t at all.

> +	union nf_inet_addr       caddr;          /* client address */
> +	union nf_inet_addr       vaddr;          /* virtual address */
> +	union nf_inet_addr       daddr;          /* destination address */
>  	__be16                   cport;
>  	__be16                   vport;
>  	__be16                   dport;
> @@ -314,8 +318,9 @@ struct ip_vs_service {
>  	atomic_t		refcnt;   /* reference counter */
>  	atomic_t		usecnt;   /* use counter */
>  
> +	u_int16_t               af;       /* address family */

ditto (also elsewhere)

>  	__u16			protocol; /* which protocol (TCP/UDP) */
> -	__be32			addr;	  /* IP address for virtual service */
> +	union nf_inet_addr	addr;	  /* IP address for virtual service */
>  	__be16			port;	  /* port number for the service */
>  	__u32                   fwmark;   /* firewall mark of the service */
>  	unsigned		flags;	  /* service status flags */
> @@ -342,7 +347,8 @@ struct ip_vs_dest {
>  	struct list_head	n_list;   /* for the dests in the service */
>  	struct list_head	d_list;   /* for table with all the dests */
>  
> -	__be32			addr;		/* IP address of the server */
> +	u_int16_t		af;		/* address family */
> +	union nf_inet_addr	addr;		/* IP address of the server */
>  	__be16			port;		/* port number of the server */
>  	volatile unsigned	flags;		/* dest status flags */
>  	atomic_t		conn_flags;	/* flags to copy to conn */
> @@ -366,7 +372,7 @@ struct ip_vs_dest {
>  	/* for virtual service */
>  	struct ip_vs_service	*svc;		/* service it belongs to */
>  	__u16			protocol;	/* which protocol (TCP/UDP) */
> -	__be32			vaddr;		/* virtual IP address */
> +	union nf_inet_addr	vaddr;		/* virtual IP address */
>  	__be16			vport;		/* virtual port number */
>  	__u32			vfwmark;	/* firewall mark of service */
>  };
> diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
> index 44a6872..c7f0c2d 100644
> --- a/net/ipv4/ipvs/ip_vs_conn.c
> +++ b/net/ipv4/ipvs/ip_vs_conn.c
> @@ -131,7 +131,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
>  	int ret;
>  
>  	/* Hash by protocol, client address and port */
> -	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
> +	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
>  
>  	ct_write_lock(hash);
>  
> @@ -162,7 +162,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
>  	int ret;
>  
>  	/* unhash it and decrease its reference counter */
> -	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
> +	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
>  
>  	ct_write_lock(hash);
>  
> @@ -197,8 +197,8 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
>  	ct_read_lock(hash);
>  
>  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -		if (s_addr==cp->caddr && s_port==cp->cport &&
> -		    d_port==cp->vport && d_addr==cp->vaddr &&
> +		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
> +		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
>  		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
>  		    protocol==cp->protocol) {
>  			/* HIT */
> @@ -243,8 +243,8 @@ struct ip_vs_conn *ip_vs_ct_in_get
>  	ct_read_lock(hash);
>  
>  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -		if (s_addr==cp->caddr && s_port==cp->cport &&
> -		    d_port==cp->vport && d_addr==cp->vaddr &&
> +		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
> +		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
>  		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
>  		    protocol==cp->protocol) {
>  			/* HIT */
> @@ -286,8 +286,8 @@ struct ip_vs_conn *ip_vs_conn_out_get
>  	ct_read_lock(hash);
>  
>  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -		if (d_addr == cp->caddr && d_port == cp->cport &&
> -		    s_port == cp->dport && s_addr == cp->daddr &&
> +		if (d_addr == cp->caddr.ip && d_port == cp->cport &&
> +		    s_port == cp->dport && s_addr == cp->daddr.ip &&
>  		    protocol == cp->protocol) {
>  			/* HIT */
>  			atomic_inc(&cp->refcnt);
> @@ -406,9 +406,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
>  		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
>  		  "dest->refcnt:%d\n",
>  		  ip_vs_proto_name(cp->protocol),
> -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
>  		  ip_vs_fwd_tag(cp), cp->state,
>  		  cp->flags, atomic_read(&cp->refcnt),
>  		  atomic_read(&dest->refcnt));
> @@ -444,8 +444,8 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
>  	struct ip_vs_dest *dest;
>  
>  	if ((cp) && (!cp->dest)) {
> -		dest = ip_vs_find_dest(cp->daddr, cp->dport,
> -				       cp->vaddr, cp->vport, cp->protocol);
> +		dest = ip_vs_find_dest(cp->daddr.ip, cp->dport,
> +				       cp->vaddr.ip, cp->vport, cp->protocol);
>  		ip_vs_bind_dest(cp, dest);
>  		return dest;
>  	} else
> @@ -468,9 +468,9 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
>  		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
>  		  "dest->refcnt:%d\n",
>  		  ip_vs_proto_name(cp->protocol),
> -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
>  		  ip_vs_fwd_tag(cp), cp->state,
>  		  cp->flags, atomic_read(&cp->refcnt),
>  		  atomic_read(&dest->refcnt));
> @@ -530,9 +530,9 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
>  			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
>  			  "-> d:%u.%u.%u.%u:%d\n",
>  			  ip_vs_proto_name(ct->protocol),
> -			  NIPQUAD(ct->caddr), ntohs(ct->cport),
> -			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
> -			  NIPQUAD(ct->daddr), ntohs(ct->dport));
> +			  NIPQUAD(ct->caddr.ip), ntohs(ct->cport),
> +			  NIPQUAD(ct->vaddr.ip), ntohs(ct->vport),
> +			  NIPQUAD(ct->daddr.ip), ntohs(ct->dport));
>  
>  		/*
>  		 * Invalidate the connection template
> @@ -641,11 +641,11 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
>  	INIT_LIST_HEAD(&cp->c_list);
>  	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
>  	cp->protocol	   = proto;
> -	cp->caddr	   = caddr;
> +	cp->caddr.ip	   = caddr;
>  	cp->cport	   = cport;
> -	cp->vaddr	   = vaddr;
> +	cp->vaddr.ip	   = vaddr;
>  	cp->vport	   = vport;
> -	cp->daddr          = daddr;
> +	cp->daddr.ip	   = daddr;
>  	cp->dport          = dport;
>  	cp->flags	   = flags;
>  	spin_lock_init(&cp->lock);
> @@ -763,9 +763,9 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
>  		seq_printf(seq,
>  			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
>  				ip_vs_proto_name(cp->protocol),
> -				ntohl(cp->caddr), ntohs(cp->cport),
> -				ntohl(cp->vaddr), ntohs(cp->vport),
> -				ntohl(cp->daddr), ntohs(cp->dport),
> +				ntohl(cp->caddr.ip), ntohs(cp->cport),
> +				ntohl(cp->vaddr.ip), ntohs(cp->vport),
> +				ntohl(cp->daddr.ip), ntohs(cp->dport),
>  				ip_vs_state_name(cp->protocol, cp->state),
>  				(cp->timer.expires-jiffies)/HZ);
>  	}
> @@ -812,9 +812,9 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
>  		seq_printf(seq,
>  			"%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
>  				ip_vs_proto_name(cp->protocol),
> -				ntohl(cp->caddr), ntohs(cp->cport),
> -				ntohl(cp->vaddr), ntohs(cp->vport),
> -				ntohl(cp->daddr), ntohs(cp->dport),
> +				ntohl(cp->caddr.ip), ntohs(cp->cport),
> +				ntohl(cp->vaddr.ip), ntohs(cp->vport),
> +				ntohl(cp->daddr.ip), ntohs(cp->dport),
>  				ip_vs_state_name(cp->protocol, cp->state),
>  				ip_vs_origin_name(cp->flags),
>  				(cp->timer.expires-jiffies)/HZ);
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 9fbf0a6..a07e5b7 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -232,14 +232,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
>  						    snet, 0,
>  						    iph->daddr,
>  						    ports[1],
> -						    dest->addr, dest->port,
> +						    dest->addr.ip, dest->port,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			else
>  				ct = ip_vs_conn_new(iph->protocol,
>  						    snet, 0,
>  						    iph->daddr, 0,
> -						    dest->addr, 0,
> +						    dest->addr.ip, 0,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			if (ct == NULL)
> @@ -286,14 +286,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
>  				ct = ip_vs_conn_new(IPPROTO_IP,
>  						    snet, 0,
>  						    htonl(svc->fwmark), 0,
> -						    dest->addr, 0,
> +						    dest->addr.ip, 0,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			else
>  				ct = ip_vs_conn_new(iph->protocol,
>  						    snet, 0,
>  						    iph->daddr, 0,
> -						    dest->addr, 0,
> +						    dest->addr.ip, 0,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			if (ct == NULL)
> @@ -313,7 +313,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
>  	cp = ip_vs_conn_new(iph->protocol,
>  			    iph->saddr, ports[0],
>  			    iph->daddr, ports[1],
> -			    dest->addr, dport,
> +			    dest->addr.ip, dport,
>  			    0,
>  			    dest);
>  	if (cp == NULL) {
> @@ -380,7 +380,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  	cp = ip_vs_conn_new(iph->protocol,
>  			    iph->saddr, pptr[0],
>  			    iph->daddr, pptr[1],
> -			    dest->addr, dest->port?dest->port:pptr[1],
> +			    dest->addr.ip, dest->port?dest->port:pptr[1],
>  			    0,
>  			    dest);
>  	if (cp == NULL)
> @@ -389,9 +389,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
>  		  "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
>  		  ip_vs_fwd_tag(cp),
> -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
>  		  cp->flags, atomic_read(&cp->refcnt));
>  
>  	ip_vs_conn_stats(cp, svc);
> @@ -526,14 +526,14 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
>  	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
>  
>  	if (inout) {
> -		iph->saddr = cp->vaddr;
> +		iph->saddr = cp->vaddr.ip;
>  		ip_send_check(iph);
> -		ciph->daddr = cp->vaddr;
> +		ciph->daddr = cp->vaddr.ip;
>  		ip_send_check(ciph);
>  	} else {
> -		iph->daddr = cp->daddr;
> +		iph->daddr = cp->daddr.ip;
>  		ip_send_check(iph);
> -		ciph->saddr = cp->daddr;
> +		ciph->saddr = cp->daddr.ip;
>  		ip_send_check(ciph);
>  	}
>  
> @@ -762,7 +762,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
>  	/* mangle the packet */
>  	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
>  		goto drop;
> -	ip_hdr(skb)->saddr = cp->vaddr;
> +	ip_hdr(skb)->saddr = cp->vaddr.ip;
>  	ip_send_check(ip_hdr(skb));
>  
>  	/* For policy routing, packets originating from this
> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> index ede101e..47644f3 100644
> --- a/net/ipv4/ipvs/ip_vs_ctl.c
> +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> @@ -317,7 +317,7 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
>  		/*
>  		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
>  		 */
> -		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port);
> +		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr.ip, svc->port);
>  		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
>  	} else {
>  		/*
> @@ -373,7 +373,7 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
>  	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
>  
>  	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
> -		if ((svc->addr == vaddr)
> +		if ((svc->addr.ip == vaddr)
>  		    && (svc->port == vport)
>  		    && (svc->protocol == protocol)) {
>  			/* HIT */
> @@ -503,7 +503,7 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
>  	 *	Hash by proto,addr,port,
>  	 *	which are the parameters of the real service.
>  	 */
> -	hash = ip_vs_rs_hashkey(dest->addr, dest->port);
> +	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
>  	list_add(&dest->d_list, &ip_vs_rtable[hash]);
>  
>  	return 1;
> @@ -543,7 +543,7 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
>  
>  	read_lock(&__ip_vs_rs_lock);
>  	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
> -		if ((dest->addr == daddr)
> +		if ((dest->addr.ip == daddr)
>  		    && (dest->port == dport)
>  		    && ((dest->protocol == protocol) ||
>  			dest->vfwmark)) {
> @@ -569,7 +569,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  	 * Find the destination for the given service
>  	 */
>  	list_for_each_entry(dest, &svc->destinations, n_list) {
> -		if ((dest->addr == daddr) && (dest->port == dport)) {
> +		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
>  			/* HIT */
>  			return dest;
>  		}
> @@ -626,14 +626,14 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
>  			  "dest->refcnt=%d\n",
>  			  dest->vfwmark,
> -			  NIPQUAD(dest->addr), ntohs(dest->port),
> +			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
>  			  atomic_read(&dest->refcnt));
> -		if (dest->addr == daddr &&
> +		if (dest->addr.ip == daddr &&
>  		    dest->port == dport &&
>  		    dest->vfwmark == svc->fwmark &&
>  		    dest->protocol == svc->protocol &&
>  		    (svc->fwmark ||
> -		     (dest->vaddr == svc->addr &&
> +		     (dest->vaddr.ip == svc->addr.ip &&
>  		      dest->vport == svc->port))) {
>  			/* HIT */
>  			return dest;
> @@ -646,7 +646,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
>  				  "from trash\n",
>  				  dest->vfwmark,
> -				  NIPQUAD(dest->addr), ntohs(dest->port));
> +				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
>  			list_del(&dest->n_list);
>  			ip_vs_dst_reset(dest);
>  			__ip_vs_unbind_svc(dest);
> @@ -779,10 +779,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
>  	}
>  
>  	dest->protocol = svc->protocol;
> -	dest->vaddr = svc->addr;
> +	dest->vaddr.ip = svc->addr.ip;
>  	dest->vport = svc->port;
>  	dest->vfwmark = svc->fwmark;
> -	dest->addr = udest->addr;
> +	dest->addr.ip = udest->addr;
>  	dest->port = udest->port;
>  
>  	atomic_set(&dest->activeconns, 0);
> @@ -847,7 +847,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
>  			  NIPQUAD(daddr), ntohs(dport),
>  			  atomic_read(&dest->refcnt),
>  			  dest->vfwmark,
> -			  NIPQUAD(dest->vaddr),
> +			  NIPQUAD(dest->vaddr.ip),
>  			  ntohs(dest->vport));
>  		__ip_vs_update_dest(svc, dest, udest);
>  
> @@ -993,7 +993,7 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
>  	} else {
>  		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
>  			  "dest->refcnt=%d\n",
> -			  NIPQUAD(dest->addr), ntohs(dest->port),
> +			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
>  			  atomic_read(&dest->refcnt));
>  		list_add(&dest->n_list, &ip_vs_dest_trash);
>  		atomic_inc(&dest->refcnt);
> @@ -1101,7 +1101,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
>  	atomic_set(&svc->refcnt, 0);
>  
>  	svc->protocol = u->protocol;
> -	svc->addr = u->addr;
> +	svc->addr.ip = u->addr;
>  	svc->port = u->port;
>  	svc->fwmark = u->fwmark;
>  	svc->flags = u->flags;
> @@ -1751,7 +1751,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
>  		if (iter->table == ip_vs_svc_table)
>  			seq_printf(seq, "%s  %08X:%04X %s ",
>  				   ip_vs_proto_name(svc->protocol),
> -				   ntohl(svc->addr),
> +				   ntohl(svc->addr.ip),
>  				   ntohs(svc->port),
>  				   svc->scheduler->name);
>  		else
> @@ -1768,7 +1768,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
>  		list_for_each_entry(dest, &svc->destinations, n_list) {
>  			seq_printf(seq,
>  				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
> -				   ntohl(dest->addr), ntohs(dest->port),
> +				   ntohl(dest->addr.ip), ntohs(dest->port),
>  				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
>  				   atomic_read(&dest->weight),
>  				   atomic_read(&dest->activeconns),
> @@ -2040,7 +2040,7 @@ static void
>  ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
>  {
>  	dst->protocol = src->protocol;
> -	dst->addr = src->addr;
> +	dst->addr = src->addr.ip;
>  	dst->port = src->port;
>  	dst->fwmark = src->fwmark;
>  	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
> @@ -2114,7 +2114,7 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
>  			if (count >= get->num_dests)
>  				break;
>  
> -			entry.addr = dest->addr;
> +			entry.addr = dest->addr.ip;
>  			entry.port = dest->port;
>  			entry.conn_flags = atomic_read(&dest->conn_flags);
>  			entry.weight = atomic_read(&dest->weight);
> diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
> index fa66824..9f9d795 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)
>  	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
>  		  "--> server %u.%u.%u.%u:%d\n",
>  		  NIPQUAD(iph->daddr),
> -		  NIPQUAD(dest->addr),
> +		  NIPQUAD(dest->addr.ip),
>  		  ntohs(dest->port));
>  
>  	return dest;
> diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
> index c1c758e..bfe5d70 100644
> --- a/net/ipv4/ipvs/ip_vs_ftp.c
> +++ b/net/ipv4/ipvs/ip_vs_ftp.c
> @@ -172,17 +172,17 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
>  
>  		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
>  			  "%u.%u.%u.%u:%d detected\n",
> -			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0);
> +			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr.ip), 0);
>  
>  		/*
>  		 * Now update or create an connection entry for it
>  		 */
>  		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
> -					  cp->caddr, 0);
> +					  cp->caddr.ip, 0);
>  		if (!n_cp) {
>  			n_cp = ip_vs_conn_new(IPPROTO_TCP,
> -					      cp->caddr, 0,
> -					      cp->vaddr, port,
> +					      cp->caddr.ip, 0,
> +					      cp->vaddr.ip, port,
>  					      from, port,
>  					      IP_VS_CONN_F_NO_CPORT,
>  					      cp->dest);
> @@ -196,7 +196,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
>  		/*
>  		 * Replace the old passive address with the new one
>  		 */
> -		from = n_cp->vaddr;
> +		from = n_cp->vaddr.ip;
>  		port = n_cp->vport;
>  		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
>  			(ntohs(port)>>8)&255, ntohs(port)&255);
> @@ -306,16 +306,16 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
>  	 */
>  	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
>  		  ip_vs_proto_name(iph->protocol),
> -		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr), 0);
> +		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
>  
>  	n_cp = ip_vs_conn_in_get(iph->protocol,
>  				 to, port,
> -				 cp->vaddr, htons(ntohs(cp->vport)-1));
> +				 cp->vaddr.ip, htons(ntohs(cp->vport)-1));
>  	if (!n_cp) {
>  		n_cp = ip_vs_conn_new(IPPROTO_TCP,
>  				      to, port,
> -				      cp->vaddr, htons(ntohs(cp->vport)-1),
> -				      cp->daddr, htons(ntohs(cp->dport)-1),
> +				      cp->vaddr.ip, htons(ntohs(cp->vport)-1),
> +				      cp->daddr.ip, htons(ntohs(cp->dport)-1),
>  				      0,
>  				      cp->dest);
>  		if (!n_cp)
> diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
> index d2a43aa..69309ed 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)
>  
>  	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  atomic_read(&least->weight), loh);
> @@ -506,7 +506,7 @@ out:
>  	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
>  		  "--> server %u.%u.%u.%u:%d\n",
>  		  NIPQUAD(iph->daddr),
> -		  NIPQUAD(dest->addr),
> +		  NIPQUAD(dest->addr.ip),
>  		  ntohs(dest->port));
>  
>  	return dest;
> diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
> index 375a1ff..51c746e 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)
>  
>  	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  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)
>  
>  	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(most->addr), ntohs(most->port),
> +		  NIPQUAD(most->addr.ip), ntohs(most->port),
>  		  atomic_read(&most->activeconns),
>  		  atomic_read(&most->refcnt),
>  		  atomic_read(&most->weight), moh);
> @@ -598,7 +598,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
>  
>  	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  atomic_read(&least->weight), loh);
> @@ -706,7 +706,7 @@ out:
>  	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
>  		  "--> server %u.%u.%u.%u:%d\n",
>  		  NIPQUAD(iph->daddr),
> -		  NIPQUAD(dest->addr),
> +		  NIPQUAD(dest->addr.ip),
>  		  ntohs(dest->port));
>  
>  	return dest;
> diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
> index 2c3de1b..551d293 100644
> --- a/net/ipv4/ipvs/ip_vs_lc.c
> +++ b/net/ipv4/ipvs/ip_vs_lc.c
> @@ -68,7 +68,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  
>  	if (least)
>  	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->inactconns));
>  
> diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
> index 5330d5a..aa0e32a 100644
> --- a/net/ipv4/ipvs/ip_vs_nq.c
> +++ b/net/ipv4/ipvs/ip_vs_nq.c
> @@ -101,7 +101,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>    out:
>  	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  atomic_read(&least->weight), loh);
> diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
> index d0ea467..15860e1 100644
> --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
> +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
> @@ -147,7 +147,7 @@ tcp_snat_handler(struct sk_buff *skb,
>  	/* Adjust TCP checksums */
>  	if (!cp->app) {
>  		/* Only port and addr are changed, do fast csum update */
> -		tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
> +		tcp_fast_csum_update(tcph, cp->daddr.ip, cp->vaddr.ip,
>  				     cp->dport, cp->vport);
>  		if (skb->ip_summed == CHECKSUM_COMPLETE)
>  			skb->ip_summed = CHECKSUM_NONE;
> @@ -155,7 +155,7 @@ tcp_snat_handler(struct sk_buff *skb,
>  		/* full checksum calculation */
>  		tcph->check = 0;
>  		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
> -		tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
> +		tcph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
>  						skb->len - tcphoff,
>  						cp->protocol, skb->csum);
>  		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
> @@ -198,7 +198,7 @@ tcp_dnat_handler(struct sk_buff *skb,
>  	 */
>  	if (!cp->app) {
>  		/* Only port and addr are changed, do fast csum update */
> -		tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
> +		tcp_fast_csum_update(tcph, cp->vaddr.ip, cp->daddr.ip,
>  				     cp->vport, cp->dport);
>  		if (skb->ip_summed == CHECKSUM_COMPLETE)
>  			skb->ip_summed = CHECKSUM_NONE;
> @@ -206,7 +206,7 @@ tcp_dnat_handler(struct sk_buff *skb,
>  		/* full checksum calculation */
>  		tcph->check = 0;
>  		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
> -		tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
> +		tcph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
>  						skb->len - tcphoff,
>  						cp->protocol, skb->csum);
>  		skb->ip_summed = CHECKSUM_UNNECESSARY;
> @@ -427,8 +427,8 @@ set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
>  			  th->fin? 'F' : '.',
>  			  th->ack? 'A' : '.',
>  			  th->rst? 'R' : '.',
> -			  NIPQUAD(cp->daddr), ntohs(cp->dport),
> -			  NIPQUAD(cp->caddr), ntohs(cp->cport),
> +			  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
> +			  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
>  			  tcp_state_name(cp->state),
>  			  tcp_state_name(new_state),
>  			  atomic_read(&cp->refcnt));
> @@ -549,8 +549,8 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
>  			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
>  				  "%u.%u.%u.%u:%u to app %s on port %u\n",
>  				  __func__,
> -				  NIPQUAD(cp->caddr), ntohs(cp->cport),
> -				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> +				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> +				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
>  				  inc->name, ntohs(inc->port));
>  			cp->app = inc;
>  			if (inc->init_conn)
> diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
> index c6be5d5..8dfad5d 100644
> --- a/net/ipv4/ipvs/ip_vs_proto_udp.c
> +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
> @@ -158,7 +158,7 @@ udp_snat_handler(struct sk_buff *skb,
>  	 */
>  	if (!cp->app && (udph->check != 0)) {
>  		/* Only port and addr are changed, do fast csum update */
> -		udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
> +		udp_fast_csum_update(udph, cp->daddr.ip, cp->vaddr.ip,
>  				     cp->dport, cp->vport);
>  		if (skb->ip_summed == CHECKSUM_COMPLETE)
>  			skb->ip_summed = CHECKSUM_NONE;
> @@ -166,7 +166,7 @@ udp_snat_handler(struct sk_buff *skb,
>  		/* full checksum calculation */
>  		udph->check = 0;
>  		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
> -		udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
> +		udph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
>  						skb->len - udphoff,
>  						cp->protocol, skb->csum);
>  		if (udph->check == 0)
> @@ -211,7 +211,7 @@ udp_dnat_handler(struct sk_buff *skb,
>  	 */
>  	if (!cp->app && (udph->check != 0)) {
>  		/* Only port and addr are changed, do fast csum update */
> -		udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
> +		udp_fast_csum_update(udph, cp->vaddr.ip, cp->daddr.ip,
>  				     cp->vport, cp->dport);
>  		if (skb->ip_summed == CHECKSUM_COMPLETE)
>  			skb->ip_summed = CHECKSUM_NONE;
> @@ -219,7 +219,7 @@ udp_dnat_handler(struct sk_buff *skb,
>  		/* full checksum calculation */
>  		udph->check = 0;
>  		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
> -		udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
> +		udph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
>  						skb->len - udphoff,
>  						cp->protocol, skb->csum);
>  		if (udph->check == 0)
> @@ -343,8 +343,8 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
>  			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
>  				  "%u.%u.%u.%u:%u to app %s on port %u\n",
>  				  __func__,
> -				  NIPQUAD(cp->caddr), ntohs(cp->cport),
> -				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> +				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> +				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
>  				  inc->name, ntohs(inc->port));
>  			cp->app = inc;
>  			if (inc->init_conn)
> diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
> index f749291..27f0b62 100644
> --- a/net/ipv4/ipvs/ip_vs_rr.c
> +++ b/net/ipv4/ipvs/ip_vs_rr.c
> @@ -76,7 +76,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  	write_unlock(&svc->sched_lock);
>  	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
>  		  "activeconns %d refcnt %d weight %d\n",
> -		  NIPQUAD(dest->addr), ntohs(dest->port),
> +		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
>  		  atomic_read(&dest->activeconns),
>  		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
>  
> diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
> index 53f73be..38b574b 100644
> --- a/net/ipv4/ipvs/ip_vs_sed.c
> +++ b/net/ipv4/ipvs/ip_vs_sed.c
> @@ -103,7 +103,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  
>  	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  atomic_read(&least->weight), loh);
> diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
> index 7b979e2..c9e54e2 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)
>  	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
>  		  "--> server %u.%u.%u.%u:%d\n",
>  		  NIPQUAD(iph->saddr),
> -		  NIPQUAD(dest->addr),
> +		  NIPQUAD(dest->addr.ip),
>  		  ntohs(dest->port));
>  
>  	return dest;
> diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
> index a652da2..2cf47b2 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)
>  	s->cport = cp->cport;
>  	s->vport = cp->vport;
>  	s->dport = cp->dport;
> -	s->caddr = cp->caddr;
> -	s->vaddr = cp->vaddr;
> -	s->daddr = cp->daddr;
> +	s->caddr = cp->caddr.ip;
> +	s->vaddr = cp->vaddr.ip;
> +	s->daddr = cp->daddr.ip;
>  	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
>  	s->state = htons(cp->state);
>  	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
> diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
> index df7ad8d..09fd993 100644
> --- a/net/ipv4/ipvs/ip_vs_wlc.c
> +++ b/net/ipv4/ipvs/ip_vs_wlc.c
> @@ -91,7 +91,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  
>  	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
>  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> -		  NIPQUAD(least->addr), ntohs(least->port),
> +		  NIPQUAD(least->addr.ip), ntohs(least->port),
>  		  atomic_read(&least->activeconns),
>  		  atomic_read(&least->refcnt),
>  		  atomic_read(&least->weight), loh);
> diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
> index 0d86a79..19c49b2 100644
> --- a/net/ipv4/ipvs/ip_vs_wrr.c
> +++ b/net/ipv4/ipvs/ip_vs_wrr.c
> @@ -197,7 +197,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
>  
>  	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
>  		  "activeconns %d refcnt %d weight %d\n",
> -		  NIPQUAD(dest->addr), ntohs(dest->port),
> +		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
>  		  atomic_read(&dest->activeconns),
>  		  atomic_read(&dest->refcnt),
>  		  atomic_read(&dest->weight));
> diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
> index 9892d4a..88199c9 100644
> --- a/net/ipv4/ipvs/ip_vs_xmit.c
> +++ b/net/ipv4/ipvs/ip_vs_xmit.c
> @@ -71,7 +71,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
>  				.oif = 0,
>  				.nl_u = {
>  					.ip4_u = {
> -						.daddr = dest->addr,
> +						.daddr = dest->addr.ip,
>  						.saddr = 0,
>  						.tos = rtos, } },
>  			};
> @@ -80,12 +80,12 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
>  				spin_unlock(&dest->dst_lock);
>  				IP_VS_DBG_RL("ip_route_output error, "
>  					     "dest: %u.%u.%u.%u\n",
> -					     NIPQUAD(dest->addr));
> +					     NIPQUAD(dest->addr.ip));
>  				return NULL;
>  			}
>  			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
>  			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
> -				  NIPQUAD(dest->addr),
> +				  NIPQUAD(dest->addr.ip),
>  				  atomic_read(&rt->u.dst.__refcnt), rtos);
>  		}
>  		spin_unlock(&dest->dst_lock);
> @@ -94,14 +94,14 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
>  			.oif = 0,
>  			.nl_u = {
>  				.ip4_u = {
> -					.daddr = cp->daddr,
> +					.daddr = cp->daddr.ip,
>  					.saddr = 0,
>  					.tos = rtos, } },
>  		};
>  
>  		if (ip_route_output_key(&init_net, &rt, &fl)) {
>  			IP_VS_DBG_RL("ip_route_output error, dest: "
> -				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr));
> +				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
>  			return NULL;
>  		}
>  	}
> @@ -264,7 +264,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
>  	/* mangle the packet */
>  	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
>  		goto tx_error;
> -	ip_hdr(skb)->daddr = cp->daddr;
> +	ip_hdr(skb)->daddr = cp->daddr.ip;
>  	ip_send_check(ip_hdr(skb));
>  
>  	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
> -- 
> 1.5.4.5

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses
  2008-09-02  5:23   ` Simon Horman
@ 2008-09-02  5:53     ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  5:53 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Tue, Sep 02, 2008 at 03:23:23PM +1000, Simon Horman wrote:
> On Mon, Sep 01, 2008 at 02:55:59PM +0200, Julius Volz wrote:
> > Introduce new 'af' fields into IPVS data structures for specifying an
> > entry's address family. Convert IP addresses to be of type union
> > nf_inet_addr.
> > 
> > Signed-off-by: Julius Volz <juliusv@google.com>
> > 
> >  19 files changed, 118 insertions(+), 112 deletions(-)
> > 
> > diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> > index a25ad24..01cabd6 100644
> > --- a/include/net/ip_vs.h
> > +++ b/include/net/ip_vs.h
> > @@ -21,6 +21,9 @@
> >  #include <linux/timer.h>
> >  
> >  #include <net/checksum.h>
> > +#include <linux/netfilter.h>		/* for union nf_inet_addr */
> > +#include <linux/ipv6.h>			/* for struct ipv6hdr */
> > +#include <net/ipv6.h>			/* for ipv6_addr_copy */
> >  
> >  #ifdef CONFIG_IP_VS_DEBUG
> >  #include <linux/net.h>
> > @@ -259,9 +262,10 @@ struct ip_vs_conn {
> >  	struct list_head        c_list;         /* hashed list heads */
> >  
> >  	/* Protocol, addresses and port numbers */
> > -	__be32                   caddr;          /* client address */
> > -	__be32                   vaddr;          /* virtual address */
> > -	__be32                   daddr;          /* destination address */
> > +	u_int16_t               af;		/* address family */
> 
> 
> I believe that the prefered style is to use __u16 for internal
> kernel structures, u16 for structures exported to userspace
> and not u_int16_t at all.

Actually, sorry, I think I got that backwards.
I think that it should be u16 for internal structures
and __u16 for ones exported to userspace.

> > +	union nf_inet_addr       caddr;          /* client address */
> > +	union nf_inet_addr       vaddr;          /* virtual address */
> > +	union nf_inet_addr       daddr;          /* destination address */
> >  	__be16                   cport;
> >  	__be16                   vport;
> >  	__be16                   dport;
> > @@ -314,8 +318,9 @@ struct ip_vs_service {
> >  	atomic_t		refcnt;   /* reference counter */
> >  	atomic_t		usecnt;   /* use counter */
> >  
> > +	u_int16_t               af;       /* address family */
> 
> ditto (also elsewhere)
> 
> >  	__u16			protocol; /* which protocol (TCP/UDP) */
> > -	__be32			addr;	  /* IP address for virtual service */
> > +	union nf_inet_addr	addr;	  /* IP address for virtual service */
> >  	__be16			port;	  /* port number for the service */
> >  	__u32                   fwmark;   /* firewall mark of the service */
> >  	unsigned		flags;	  /* service status flags */
> > @@ -342,7 +347,8 @@ struct ip_vs_dest {
> >  	struct list_head	n_list;   /* for the dests in the service */
> >  	struct list_head	d_list;   /* for table with all the dests */
> >  
> > -	__be32			addr;		/* IP address of the server */
> > +	u_int16_t		af;		/* address family */
> > +	union nf_inet_addr	addr;		/* IP address of the server */
> >  	__be16			port;		/* port number of the server */
> >  	volatile unsigned	flags;		/* dest status flags */
> >  	atomic_t		conn_flags;	/* flags to copy to conn */
> > @@ -366,7 +372,7 @@ struct ip_vs_dest {
> >  	/* for virtual service */
> >  	struct ip_vs_service	*svc;		/* service it belongs to */
> >  	__u16			protocol;	/* which protocol (TCP/UDP) */
> > -	__be32			vaddr;		/* virtual IP address */
> > +	union nf_inet_addr	vaddr;		/* virtual IP address */
> >  	__be16			vport;		/* virtual port number */
> >  	__u32			vfwmark;	/* firewall mark of service */
> >  };
> > diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
> > index 44a6872..c7f0c2d 100644
> > --- a/net/ipv4/ipvs/ip_vs_conn.c
> > +++ b/net/ipv4/ipvs/ip_vs_conn.c
> > @@ -131,7 +131,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
> >  	int ret;
> >  
> >  	/* Hash by protocol, client address and port */
> > -	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
> > +	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
> >  
> >  	ct_write_lock(hash);
> >  
> > @@ -162,7 +162,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
> >  	int ret;
> >  
> >  	/* unhash it and decrease its reference counter */
> > -	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
> > +	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr.ip, cp->cport);
> >  
> >  	ct_write_lock(hash);
> >  
> > @@ -197,8 +197,8 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
> >  	ct_read_lock(hash);
> >  
> >  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> > -		if (s_addr==cp->caddr && s_port==cp->cport &&
> > -		    d_port==cp->vport && d_addr==cp->vaddr &&
> > +		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
> > +		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
> >  		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
> >  		    protocol==cp->protocol) {
> >  			/* HIT */
> > @@ -243,8 +243,8 @@ struct ip_vs_conn *ip_vs_ct_in_get
> >  	ct_read_lock(hash);
> >  
> >  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> > -		if (s_addr==cp->caddr && s_port==cp->cport &&
> > -		    d_port==cp->vport && d_addr==cp->vaddr &&
> > +		if (s_addr==cp->caddr.ip && s_port==cp->cport &&
> > +		    d_port==cp->vport && d_addr==cp->vaddr.ip &&
> >  		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
> >  		    protocol==cp->protocol) {
> >  			/* HIT */
> > @@ -286,8 +286,8 @@ struct ip_vs_conn *ip_vs_conn_out_get
> >  	ct_read_lock(hash);
> >  
> >  	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> > -		if (d_addr == cp->caddr && d_port == cp->cport &&
> > -		    s_port == cp->dport && s_addr == cp->daddr &&
> > +		if (d_addr == cp->caddr.ip && d_port == cp->cport &&
> > +		    s_port == cp->dport && s_addr == cp->daddr.ip &&
> >  		    protocol == cp->protocol) {
> >  			/* HIT */
> >  			atomic_inc(&cp->refcnt);
> > @@ -406,9 +406,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
> >  		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
> >  		  "dest->refcnt:%d\n",
> >  		  ip_vs_proto_name(cp->protocol),
> > -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> > -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> > +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> > +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> > +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
> >  		  ip_vs_fwd_tag(cp), cp->state,
> >  		  cp->flags, atomic_read(&cp->refcnt),
> >  		  atomic_read(&dest->refcnt));
> > @@ -444,8 +444,8 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
> >  	struct ip_vs_dest *dest;
> >  
> >  	if ((cp) && (!cp->dest)) {
> > -		dest = ip_vs_find_dest(cp->daddr, cp->dport,
> > -				       cp->vaddr, cp->vport, cp->protocol);
> > +		dest = ip_vs_find_dest(cp->daddr.ip, cp->dport,
> > +				       cp->vaddr.ip, cp->vport, cp->protocol);
> >  		ip_vs_bind_dest(cp, dest);
> >  		return dest;
> >  	} else
> > @@ -468,9 +468,9 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
> >  		  "d:%u.%u.%u.%u:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d "
> >  		  "dest->refcnt:%d\n",
> >  		  ip_vs_proto_name(cp->protocol),
> > -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> > -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> > +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> > +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> > +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
> >  		  ip_vs_fwd_tag(cp), cp->state,
> >  		  cp->flags, atomic_read(&cp->refcnt),
> >  		  atomic_read(&dest->refcnt));
> > @@ -530,9 +530,9 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
> >  			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
> >  			  "-> d:%u.%u.%u.%u:%d\n",
> >  			  ip_vs_proto_name(ct->protocol),
> > -			  NIPQUAD(ct->caddr), ntohs(ct->cport),
> > -			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
> > -			  NIPQUAD(ct->daddr), ntohs(ct->dport));
> > +			  NIPQUAD(ct->caddr.ip), ntohs(ct->cport),
> > +			  NIPQUAD(ct->vaddr.ip), ntohs(ct->vport),
> > +			  NIPQUAD(ct->daddr.ip), ntohs(ct->dport));
> >  
> >  		/*
> >  		 * Invalidate the connection template
> > @@ -641,11 +641,11 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
> >  	INIT_LIST_HEAD(&cp->c_list);
> >  	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
> >  	cp->protocol	   = proto;
> > -	cp->caddr	   = caddr;
> > +	cp->caddr.ip	   = caddr;
> >  	cp->cport	   = cport;
> > -	cp->vaddr	   = vaddr;
> > +	cp->vaddr.ip	   = vaddr;
> >  	cp->vport	   = vport;
> > -	cp->daddr          = daddr;
> > +	cp->daddr.ip	   = daddr;
> >  	cp->dport          = dport;
> >  	cp->flags	   = flags;
> >  	spin_lock_init(&cp->lock);
> > @@ -763,9 +763,9 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
> >  		seq_printf(seq,
> >  			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
> >  				ip_vs_proto_name(cp->protocol),
> > -				ntohl(cp->caddr), ntohs(cp->cport),
> > -				ntohl(cp->vaddr), ntohs(cp->vport),
> > -				ntohl(cp->daddr), ntohs(cp->dport),
> > +				ntohl(cp->caddr.ip), ntohs(cp->cport),
> > +				ntohl(cp->vaddr.ip), ntohs(cp->vport),
> > +				ntohl(cp->daddr.ip), ntohs(cp->dport),
> >  				ip_vs_state_name(cp->protocol, cp->state),
> >  				(cp->timer.expires-jiffies)/HZ);
> >  	}
> > @@ -812,9 +812,9 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
> >  		seq_printf(seq,
> >  			"%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
> >  				ip_vs_proto_name(cp->protocol),
> > -				ntohl(cp->caddr), ntohs(cp->cport),
> > -				ntohl(cp->vaddr), ntohs(cp->vport),
> > -				ntohl(cp->daddr), ntohs(cp->dport),
> > +				ntohl(cp->caddr.ip), ntohs(cp->cport),
> > +				ntohl(cp->vaddr.ip), ntohs(cp->vport),
> > +				ntohl(cp->daddr.ip), ntohs(cp->dport),
> >  				ip_vs_state_name(cp->protocol, cp->state),
> >  				ip_vs_origin_name(cp->flags),
> >  				(cp->timer.expires-jiffies)/HZ);
> > diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> > index 9fbf0a6..a07e5b7 100644
> > --- a/net/ipv4/ipvs/ip_vs_core.c
> > +++ b/net/ipv4/ipvs/ip_vs_core.c
> > @@ -232,14 +232,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
> >  						    snet, 0,
> >  						    iph->daddr,
> >  						    ports[1],
> > -						    dest->addr, dest->port,
> > +						    dest->addr.ip, dest->port,
> >  						    IP_VS_CONN_F_TEMPLATE,
> >  						    dest);
> >  			else
> >  				ct = ip_vs_conn_new(iph->protocol,
> >  						    snet, 0,
> >  						    iph->daddr, 0,
> > -						    dest->addr, 0,
> > +						    dest->addr.ip, 0,
> >  						    IP_VS_CONN_F_TEMPLATE,
> >  						    dest);
> >  			if (ct == NULL)
> > @@ -286,14 +286,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
> >  				ct = ip_vs_conn_new(IPPROTO_IP,
> >  						    snet, 0,
> >  						    htonl(svc->fwmark), 0,
> > -						    dest->addr, 0,
> > +						    dest->addr.ip, 0,
> >  						    IP_VS_CONN_F_TEMPLATE,
> >  						    dest);
> >  			else
> >  				ct = ip_vs_conn_new(iph->protocol,
> >  						    snet, 0,
> >  						    iph->daddr, 0,
> > -						    dest->addr, 0,
> > +						    dest->addr.ip, 0,
> >  						    IP_VS_CONN_F_TEMPLATE,
> >  						    dest);
> >  			if (ct == NULL)
> > @@ -313,7 +313,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
> >  	cp = ip_vs_conn_new(iph->protocol,
> >  			    iph->saddr, ports[0],
> >  			    iph->daddr, ports[1],
> > -			    dest->addr, dport,
> > +			    dest->addr.ip, dport,
> >  			    0,
> >  			    dest);
> >  	if (cp == NULL) {
> > @@ -380,7 +380,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  	cp = ip_vs_conn_new(iph->protocol,
> >  			    iph->saddr, pptr[0],
> >  			    iph->daddr, pptr[1],
> > -			    dest->addr, dest->port?dest->port:pptr[1],
> > +			    dest->addr.ip, dest->port?dest->port:pptr[1],
> >  			    0,
> >  			    dest);
> >  	if (cp == NULL)
> > @@ -389,9 +389,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  	IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
> >  		  "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
> >  		  ip_vs_fwd_tag(cp),
> > -		  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > -		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> > -		  NIPQUAD(cp->daddr), ntohs(cp->dport),
> > +		  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> > +		  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> > +		  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
> >  		  cp->flags, atomic_read(&cp->refcnt));
> >  
> >  	ip_vs_conn_stats(cp, svc);
> > @@ -526,14 +526,14 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
> >  	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
> >  
> >  	if (inout) {
> > -		iph->saddr = cp->vaddr;
> > +		iph->saddr = cp->vaddr.ip;
> >  		ip_send_check(iph);
> > -		ciph->daddr = cp->vaddr;
> > +		ciph->daddr = cp->vaddr.ip;
> >  		ip_send_check(ciph);
> >  	} else {
> > -		iph->daddr = cp->daddr;
> > +		iph->daddr = cp->daddr.ip;
> >  		ip_send_check(iph);
> > -		ciph->saddr = cp->daddr;
> > +		ciph->saddr = cp->daddr.ip;
> >  		ip_send_check(ciph);
> >  	}
> >  
> > @@ -762,7 +762,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
> >  	/* mangle the packet */
> >  	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
> >  		goto drop;
> > -	ip_hdr(skb)->saddr = cp->vaddr;
> > +	ip_hdr(skb)->saddr = cp->vaddr.ip;
> >  	ip_send_check(ip_hdr(skb));
> >  
> >  	/* For policy routing, packets originating from this
> > diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> > index ede101e..47644f3 100644
> > --- a/net/ipv4/ipvs/ip_vs_ctl.c
> > +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> > @@ -317,7 +317,7 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
> >  		/*
> >  		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
> >  		 */
> > -		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port);
> > +		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr.ip, svc->port);
> >  		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
> >  	} else {
> >  		/*
> > @@ -373,7 +373,7 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
> >  	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
> >  
> >  	list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
> > -		if ((svc->addr == vaddr)
> > +		if ((svc->addr.ip == vaddr)
> >  		    && (svc->port == vport)
> >  		    && (svc->protocol == protocol)) {
> >  			/* HIT */
> > @@ -503,7 +503,7 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
> >  	 *	Hash by proto,addr,port,
> >  	 *	which are the parameters of the real service.
> >  	 */
> > -	hash = ip_vs_rs_hashkey(dest->addr, dest->port);
> > +	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
> >  	list_add(&dest->d_list, &ip_vs_rtable[hash]);
> >  
> >  	return 1;
> > @@ -543,7 +543,7 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
> >  
> >  	read_lock(&__ip_vs_rs_lock);
> >  	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
> > -		if ((dest->addr == daddr)
> > +		if ((dest->addr.ip == daddr)
> >  		    && (dest->port == dport)
> >  		    && ((dest->protocol == protocol) ||
> >  			dest->vfwmark)) {
> > @@ -569,7 +569,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
> >  	 * Find the destination for the given service
> >  	 */
> >  	list_for_each_entry(dest, &svc->destinations, n_list) {
> > -		if ((dest->addr == daddr) && (dest->port == dport)) {
> > +		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
> >  			/* HIT */
> >  			return dest;
> >  		}
> > @@ -626,14 +626,14 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
> >  		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
> >  			  "dest->refcnt=%d\n",
> >  			  dest->vfwmark,
> > -			  NIPQUAD(dest->addr), ntohs(dest->port),
> > +			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
> >  			  atomic_read(&dest->refcnt));
> > -		if (dest->addr == daddr &&
> > +		if (dest->addr.ip == daddr &&
> >  		    dest->port == dport &&
> >  		    dest->vfwmark == svc->fwmark &&
> >  		    dest->protocol == svc->protocol &&
> >  		    (svc->fwmark ||
> > -		     (dest->vaddr == svc->addr &&
> > +		     (dest->vaddr.ip == svc->addr.ip &&
> >  		      dest->vport == svc->port))) {
> >  			/* HIT */
> >  			return dest;
> > @@ -646,7 +646,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
> >  			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
> >  				  "from trash\n",
> >  				  dest->vfwmark,
> > -				  NIPQUAD(dest->addr), ntohs(dest->port));
> > +				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
> >  			list_del(&dest->n_list);
> >  			ip_vs_dst_reset(dest);
> >  			__ip_vs_unbind_svc(dest);
> > @@ -779,10 +779,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
> >  	}
> >  
> >  	dest->protocol = svc->protocol;
> > -	dest->vaddr = svc->addr;
> > +	dest->vaddr.ip = svc->addr.ip;
> >  	dest->vport = svc->port;
> >  	dest->vfwmark = svc->fwmark;
> > -	dest->addr = udest->addr;
> > +	dest->addr.ip = udest->addr;
> >  	dest->port = udest->port;
> >  
> >  	atomic_set(&dest->activeconns, 0);
> > @@ -847,7 +847,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
> >  			  NIPQUAD(daddr), ntohs(dport),
> >  			  atomic_read(&dest->refcnt),
> >  			  dest->vfwmark,
> > -			  NIPQUAD(dest->vaddr),
> > +			  NIPQUAD(dest->vaddr.ip),
> >  			  ntohs(dest->vport));
> >  		__ip_vs_update_dest(svc, dest, udest);
> >  
> > @@ -993,7 +993,7 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
> >  	} else {
> >  		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
> >  			  "dest->refcnt=%d\n",
> > -			  NIPQUAD(dest->addr), ntohs(dest->port),
> > +			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
> >  			  atomic_read(&dest->refcnt));
> >  		list_add(&dest->n_list, &ip_vs_dest_trash);
> >  		atomic_inc(&dest->refcnt);
> > @@ -1101,7 +1101,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
> >  	atomic_set(&svc->refcnt, 0);
> >  
> >  	svc->protocol = u->protocol;
> > -	svc->addr = u->addr;
> > +	svc->addr.ip = u->addr;
> >  	svc->port = u->port;
> >  	svc->fwmark = u->fwmark;
> >  	svc->flags = u->flags;
> > @@ -1751,7 +1751,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
> >  		if (iter->table == ip_vs_svc_table)
> >  			seq_printf(seq, "%s  %08X:%04X %s ",
> >  				   ip_vs_proto_name(svc->protocol),
> > -				   ntohl(svc->addr),
> > +				   ntohl(svc->addr.ip),
> >  				   ntohs(svc->port),
> >  				   svc->scheduler->name);
> >  		else
> > @@ -1768,7 +1768,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
> >  		list_for_each_entry(dest, &svc->destinations, n_list) {
> >  			seq_printf(seq,
> >  				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
> > -				   ntohl(dest->addr), ntohs(dest->port),
> > +				   ntohl(dest->addr.ip), ntohs(dest->port),
> >  				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
> >  				   atomic_read(&dest->weight),
> >  				   atomic_read(&dest->activeconns),
> > @@ -2040,7 +2040,7 @@ static void
> >  ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
> >  {
> >  	dst->protocol = src->protocol;
> > -	dst->addr = src->addr;
> > +	dst->addr = src->addr.ip;
> >  	dst->port = src->port;
> >  	dst->fwmark = src->fwmark;
> >  	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
> > @@ -2114,7 +2114,7 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
> >  			if (count >= get->num_dests)
> >  				break;
> >  
> > -			entry.addr = dest->addr;
> > +			entry.addr = dest->addr.ip;
> >  			entry.port = dest->port;
> >  			entry.conn_flags = atomic_read(&dest->conn_flags);
> >  			entry.weight = atomic_read(&dest->weight);
> > diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
> > index fa66824..9f9d795 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)
> >  	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
> >  		  "--> server %u.%u.%u.%u:%d\n",
> >  		  NIPQUAD(iph->daddr),
> > -		  NIPQUAD(dest->addr),
> > +		  NIPQUAD(dest->addr.ip),
> >  		  ntohs(dest->port));
> >  
> >  	return dest;
> > diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
> > index c1c758e..bfe5d70 100644
> > --- a/net/ipv4/ipvs/ip_vs_ftp.c
> > +++ b/net/ipv4/ipvs/ip_vs_ftp.c
> > @@ -172,17 +172,17 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
> >  
> >  		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
> >  			  "%u.%u.%u.%u:%d detected\n",
> > -			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0);
> > +			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr.ip), 0);
> >  
> >  		/*
> >  		 * Now update or create an connection entry for it
> >  		 */
> >  		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
> > -					  cp->caddr, 0);
> > +					  cp->caddr.ip, 0);
> >  		if (!n_cp) {
> >  			n_cp = ip_vs_conn_new(IPPROTO_TCP,
> > -					      cp->caddr, 0,
> > -					      cp->vaddr, port,
> > +					      cp->caddr.ip, 0,
> > +					      cp->vaddr.ip, port,
> >  					      from, port,
> >  					      IP_VS_CONN_F_NO_CPORT,
> >  					      cp->dest);
> > @@ -196,7 +196,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
> >  		/*
> >  		 * Replace the old passive address with the new one
> >  		 */
> > -		from = n_cp->vaddr;
> > +		from = n_cp->vaddr.ip;
> >  		port = n_cp->vport;
> >  		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
> >  			(ntohs(port)>>8)&255, ntohs(port)&255);
> > @@ -306,16 +306,16 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
> >  	 */
> >  	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
> >  		  ip_vs_proto_name(iph->protocol),
> > -		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr), 0);
> > +		  NIPQUAD(to), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
> >  
> >  	n_cp = ip_vs_conn_in_get(iph->protocol,
> >  				 to, port,
> > -				 cp->vaddr, htons(ntohs(cp->vport)-1));
> > +				 cp->vaddr.ip, htons(ntohs(cp->vport)-1));
> >  	if (!n_cp) {
> >  		n_cp = ip_vs_conn_new(IPPROTO_TCP,
> >  				      to, port,
> > -				      cp->vaddr, htons(ntohs(cp->vport)-1),
> > -				      cp->daddr, htons(ntohs(cp->dport)-1),
> > +				      cp->vaddr.ip, htons(ntohs(cp->vport)-1),
> > +				      cp->daddr.ip, htons(ntohs(cp->dport)-1),
> >  				      0,
> >  				      cp->dest);
> >  		if (!n_cp)
> > diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
> > index d2a43aa..69309ed 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)
> >  
> >  	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  atomic_read(&least->weight), loh);
> > @@ -506,7 +506,7 @@ out:
> >  	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
> >  		  "--> server %u.%u.%u.%u:%d\n",
> >  		  NIPQUAD(iph->daddr),
> > -		  NIPQUAD(dest->addr),
> > +		  NIPQUAD(dest->addr.ip),
> >  		  ntohs(dest->port));
> >  
> >  	return dest;
> > diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
> > index 375a1ff..51c746e 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)
> >  
> >  	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  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)
> >  
> >  	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(most->addr), ntohs(most->port),
> > +		  NIPQUAD(most->addr.ip), ntohs(most->port),
> >  		  atomic_read(&most->activeconns),
> >  		  atomic_read(&most->refcnt),
> >  		  atomic_read(&most->weight), moh);
> > @@ -598,7 +598,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
> >  
> >  	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  atomic_read(&least->weight), loh);
> > @@ -706,7 +706,7 @@ out:
> >  	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
> >  		  "--> server %u.%u.%u.%u:%d\n",
> >  		  NIPQUAD(iph->daddr),
> > -		  NIPQUAD(dest->addr),
> > +		  NIPQUAD(dest->addr.ip),
> >  		  ntohs(dest->port));
> >  
> >  	return dest;
> > diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
> > index 2c3de1b..551d293 100644
> > --- a/net/ipv4/ipvs/ip_vs_lc.c
> > +++ b/net/ipv4/ipvs/ip_vs_lc.c
> > @@ -68,7 +68,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  
> >  	if (least)
> >  	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->inactconns));
> >  
> > diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
> > index 5330d5a..aa0e32a 100644
> > --- a/net/ipv4/ipvs/ip_vs_nq.c
> > +++ b/net/ipv4/ipvs/ip_vs_nq.c
> > @@ -101,7 +101,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >    out:
> >  	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  atomic_read(&least->weight), loh);
> > diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
> > index d0ea467..15860e1 100644
> > --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
> > +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
> > @@ -147,7 +147,7 @@ tcp_snat_handler(struct sk_buff *skb,
> >  	/* Adjust TCP checksums */
> >  	if (!cp->app) {
> >  		/* Only port and addr are changed, do fast csum update */
> > -		tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr,
> > +		tcp_fast_csum_update(tcph, cp->daddr.ip, cp->vaddr.ip,
> >  				     cp->dport, cp->vport);
> >  		if (skb->ip_summed == CHECKSUM_COMPLETE)
> >  			skb->ip_summed = CHECKSUM_NONE;
> > @@ -155,7 +155,7 @@ tcp_snat_handler(struct sk_buff *skb,
> >  		/* full checksum calculation */
> >  		tcph->check = 0;
> >  		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
> > -		tcph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
> > +		tcph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
> >  						skb->len - tcphoff,
> >  						cp->protocol, skb->csum);
> >  		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
> > @@ -198,7 +198,7 @@ tcp_dnat_handler(struct sk_buff *skb,
> >  	 */
> >  	if (!cp->app) {
> >  		/* Only port and addr are changed, do fast csum update */
> > -		tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
> > +		tcp_fast_csum_update(tcph, cp->vaddr.ip, cp->daddr.ip,
> >  				     cp->vport, cp->dport);
> >  		if (skb->ip_summed == CHECKSUM_COMPLETE)
> >  			skb->ip_summed = CHECKSUM_NONE;
> > @@ -206,7 +206,7 @@ tcp_dnat_handler(struct sk_buff *skb,
> >  		/* full checksum calculation */
> >  		tcph->check = 0;
> >  		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
> > -		tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
> > +		tcph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
> >  						skb->len - tcphoff,
> >  						cp->protocol, skb->csum);
> >  		skb->ip_summed = CHECKSUM_UNNECESSARY;
> > @@ -427,8 +427,8 @@ set_tcp_state(struct ip_vs_protocol *pp, struct ip_vs_conn *cp,
> >  			  th->fin? 'F' : '.',
> >  			  th->ack? 'A' : '.',
> >  			  th->rst? 'R' : '.',
> > -			  NIPQUAD(cp->daddr), ntohs(cp->dport),
> > -			  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > +			  NIPQUAD(cp->daddr.ip), ntohs(cp->dport),
> > +			  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> >  			  tcp_state_name(cp->state),
> >  			  tcp_state_name(new_state),
> >  			  atomic_read(&cp->refcnt));
> > @@ -549,8 +549,8 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
> >  			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
> >  				  "%u.%u.%u.%u:%u to app %s on port %u\n",
> >  				  __func__,
> > -				  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > -				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> > +				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> > +				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> >  				  inc->name, ntohs(inc->port));
> >  			cp->app = inc;
> >  			if (inc->init_conn)
> > diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
> > index c6be5d5..8dfad5d 100644
> > --- a/net/ipv4/ipvs/ip_vs_proto_udp.c
> > +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
> > @@ -158,7 +158,7 @@ udp_snat_handler(struct sk_buff *skb,
> >  	 */
> >  	if (!cp->app && (udph->check != 0)) {
> >  		/* Only port and addr are changed, do fast csum update */
> > -		udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
> > +		udp_fast_csum_update(udph, cp->daddr.ip, cp->vaddr.ip,
> >  				     cp->dport, cp->vport);
> >  		if (skb->ip_summed == CHECKSUM_COMPLETE)
> >  			skb->ip_summed = CHECKSUM_NONE;
> > @@ -166,7 +166,7 @@ udp_snat_handler(struct sk_buff *skb,
> >  		/* full checksum calculation */
> >  		udph->check = 0;
> >  		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
> > -		udph->check = csum_tcpudp_magic(cp->vaddr, cp->caddr,
> > +		udph->check = csum_tcpudp_magic(cp->vaddr.ip, cp->caddr.ip,
> >  						skb->len - udphoff,
> >  						cp->protocol, skb->csum);
> >  		if (udph->check == 0)
> > @@ -211,7 +211,7 @@ udp_dnat_handler(struct sk_buff *skb,
> >  	 */
> >  	if (!cp->app && (udph->check != 0)) {
> >  		/* Only port and addr are changed, do fast csum update */
> > -		udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
> > +		udp_fast_csum_update(udph, cp->vaddr.ip, cp->daddr.ip,
> >  				     cp->vport, cp->dport);
> >  		if (skb->ip_summed == CHECKSUM_COMPLETE)
> >  			skb->ip_summed = CHECKSUM_NONE;
> > @@ -219,7 +219,7 @@ udp_dnat_handler(struct sk_buff *skb,
> >  		/* full checksum calculation */
> >  		udph->check = 0;
> >  		skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
> > -		udph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
> > +		udph->check = csum_tcpudp_magic(cp->caddr.ip, cp->daddr.ip,
> >  						skb->len - udphoff,
> >  						cp->protocol, skb->csum);
> >  		if (udph->check == 0)
> > @@ -343,8 +343,8 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
> >  			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
> >  				  "%u.%u.%u.%u:%u to app %s on port %u\n",
> >  				  __func__,
> > -				  NIPQUAD(cp->caddr), ntohs(cp->cport),
> > -				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
> > +				  NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
> > +				  NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
> >  				  inc->name, ntohs(inc->port));
> >  			cp->app = inc;
> >  			if (inc->init_conn)
> > diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
> > index f749291..27f0b62 100644
> > --- a/net/ipv4/ipvs/ip_vs_rr.c
> > +++ b/net/ipv4/ipvs/ip_vs_rr.c
> > @@ -76,7 +76,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  	write_unlock(&svc->sched_lock);
> >  	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
> >  		  "activeconns %d refcnt %d weight %d\n",
> > -		  NIPQUAD(dest->addr), ntohs(dest->port),
> > +		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
> >  		  atomic_read(&dest->activeconns),
> >  		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
> >  
> > diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
> > index 53f73be..38b574b 100644
> > --- a/net/ipv4/ipvs/ip_vs_sed.c
> > +++ b/net/ipv4/ipvs/ip_vs_sed.c
> > @@ -103,7 +103,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  
> >  	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  atomic_read(&least->weight), loh);
> > diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
> > index 7b979e2..c9e54e2 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)
> >  	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
> >  		  "--> server %u.%u.%u.%u:%d\n",
> >  		  NIPQUAD(iph->saddr),
> > -		  NIPQUAD(dest->addr),
> > +		  NIPQUAD(dest->addr.ip),
> >  		  ntohs(dest->port));
> >  
> >  	return dest;
> > diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
> > index a652da2..2cf47b2 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)
> >  	s->cport = cp->cport;
> >  	s->vport = cp->vport;
> >  	s->dport = cp->dport;
> > -	s->caddr = cp->caddr;
> > -	s->vaddr = cp->vaddr;
> > -	s->daddr = cp->daddr;
> > +	s->caddr = cp->caddr.ip;
> > +	s->vaddr = cp->vaddr.ip;
> > +	s->daddr = cp->daddr.ip;
> >  	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
> >  	s->state = htons(cp->state);
> >  	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
> > diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
> > index df7ad8d..09fd993 100644
> > --- a/net/ipv4/ipvs/ip_vs_wlc.c
> > +++ b/net/ipv4/ipvs/ip_vs_wlc.c
> > @@ -91,7 +91,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  
> >  	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
> >  		  "activeconns %d refcnt %d weight %d overhead %d\n",
> > -		  NIPQUAD(least->addr), ntohs(least->port),
> > +		  NIPQUAD(least->addr.ip), ntohs(least->port),
> >  		  atomic_read(&least->activeconns),
> >  		  atomic_read(&least->refcnt),
> >  		  atomic_read(&least->weight), loh);
> > diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
> > index 0d86a79..19c49b2 100644
> > --- a/net/ipv4/ipvs/ip_vs_wrr.c
> > +++ b/net/ipv4/ipvs/ip_vs_wrr.c
> > @@ -197,7 +197,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
> >  
> >  	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
> >  		  "activeconns %d refcnt %d weight %d\n",
> > -		  NIPQUAD(dest->addr), ntohs(dest->port),
> > +		  NIPQUAD(dest->addr.ip), ntohs(dest->port),
> >  		  atomic_read(&dest->activeconns),
> >  		  atomic_read(&dest->refcnt),
> >  		  atomic_read(&dest->weight));
> > diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
> > index 9892d4a..88199c9 100644
> > --- a/net/ipv4/ipvs/ip_vs_xmit.c
> > +++ b/net/ipv4/ipvs/ip_vs_xmit.c
> > @@ -71,7 +71,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
> >  				.oif = 0,
> >  				.nl_u = {
> >  					.ip4_u = {
> > -						.daddr = dest->addr,
> > +						.daddr = dest->addr.ip,
> >  						.saddr = 0,
> >  						.tos = rtos, } },
> >  			};
> > @@ -80,12 +80,12 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
> >  				spin_unlock(&dest->dst_lock);
> >  				IP_VS_DBG_RL("ip_route_output error, "
> >  					     "dest: %u.%u.%u.%u\n",
> > -					     NIPQUAD(dest->addr));
> > +					     NIPQUAD(dest->addr.ip));
> >  				return NULL;
> >  			}
> >  			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
> >  			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
> > -				  NIPQUAD(dest->addr),
> > +				  NIPQUAD(dest->addr.ip),
> >  				  atomic_read(&rt->u.dst.__refcnt), rtos);
> >  		}
> >  		spin_unlock(&dest->dst_lock);
> > @@ -94,14 +94,14 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
> >  			.oif = 0,
> >  			.nl_u = {
> >  				.ip4_u = {
> > -					.daddr = cp->daddr,
> > +					.daddr = cp->daddr.ip,
> >  					.saddr = 0,
> >  					.tos = rtos, } },
> >  		};
> >  
> >  		if (ip_route_output_key(&init_net, &rt, &fl)) {
> >  			IP_VS_DBG_RL("ip_route_output error, dest: "
> > -				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr));
> > +				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
> >  			return NULL;
> >  		}
> >  	}
> > @@ -264,7 +264,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
> >  	/* mangle the packet */
> >  	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
> >  		goto tx_error;
> > -	ip_hdr(skb)->daddr = cp->daddr;
> > +	ip_hdr(skb)->daddr = cp->daddr.ip;
> >  	ip_send_check(ip_hdr(skb));
> >  
> >  	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
> > -- 
> > 1.5.4.5
> --
> To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs
  2008-09-01 12:56 ` [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs Julius Volz
@ 2008-09-02  6:06   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  6:06 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:02PM +0200, Julius Volz wrote:
> Add extended internal versions of struct ip_vs_service_user and struct
> ip_vs_dest_user (the originals can't be modified as they are part
> of the old sockopt interface). Adjust ip_vs_ctl.c to work with the new
> data structures and add some minor AF-awareness.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>
> 
>  2 files changed, 129 insertions(+), 48 deletions(-)
> 
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index 45a7458..9657bd4 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -400,6 +400,45 @@ struct ip_vs_conn {
>  
>  
>  /*
> + *	Extended internal versions of struct ip_vs_service_user and
> + *	ip_vs_dest_user for IPv6 support.
> + *
> + *	We need these to conveniently pass around service and destination
> + *	options, but unfortunately, we also need to keep the old definitions to
> + *	maintain userspace backwards compatibility for the setsockopt interface.
> + */
> +struct ip_vs_service_user_kern {
> +	/* virtual service addresses */
> +	u_int16_t		af;
> +	u_int16_t		protocol;
> +	union nf_inet_addr	addr;		/* virtual ip address */
> +	__be16			port;
> +	u_int32_t		fwmark;		/* firwall mark of service */
> +
> +	/* virtual service options */
> +	char			*sched_name;
> +	unsigned		flags;		/* virtual service flags */
> +	unsigned		timeout;	/* persistent timeout in sec */
> +	__be32			netmask;	/* persistent netmask */
> +};

As this is an internal structure I beleive that u_int16_t and u_int32_t
should be u16 and u32 respectively.

> +struct ip_vs_dest_user_kern {
> +	/* destination server address */
> +	union nf_inet_addr	addr;
> +	__be16			port;
> +
> +	/* real server options */
> +	unsigned		conn_flags;	/* connection flags */
> +	int			weight;		/* destination weight */
> +
> +	/* thresholds for active connections */
> +	u_int32_t		u_threshold;	/* upper threshold */
> +	u_int32_t		l_threshold;	/* lower threshold */
> +};

ditto

> +
> +
> +/*
>   *	The information about the virtual service offered to the net
>   *	and the forwarding entries
>   */
> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> index 47644f3..52b3c1e 100644
> --- a/net/ipv4/ipvs/ip_vs_ctl.c
> +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> @@ -707,7 +707,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
>   */
>  static void
>  __ip_vs_update_dest(struct ip_vs_service *svc,
> -		    struct ip_vs_dest *dest, struct ip_vs_dest_user *udest)
> +		    struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
>  {
>  	int conn_flags;
>  
> @@ -716,7 +716,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
>  	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
>  
>  	/* check if local node and update the flags */
> -	if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) {
> +	if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
>  		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
>  			| IP_VS_CONN_F_LOCALNODE;
>  	}
> @@ -760,7 +760,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
>   *	Create a destination for the given service
>   */
>  static int
> -ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
> +ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
>  	       struct ip_vs_dest **dest_p)
>  {
>  	struct ip_vs_dest *dest;
> @@ -768,7 +768,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
>  
>  	EnterFunction(2);
>  
> -	atype = inet_addr_type(&init_net, udest->addr);
> +	atype = inet_addr_type(&init_net, udest->addr.ip);
>  	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
>  		return -EINVAL;
>  
> @@ -778,11 +778,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
>  		return -ENOMEM;
>  	}
>  
> +	dest->af = svc->af;
>  	dest->protocol = svc->protocol;
> -	dest->vaddr.ip = svc->addr.ip;
> +	dest->vaddr = svc->addr;
>  	dest->vport = svc->port;
>  	dest->vfwmark = svc->fwmark;
> -	dest->addr.ip = udest->addr;
> +	ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
>  	dest->port = udest->port;
>  
>  	atomic_set(&dest->activeconns, 0);
> @@ -807,10 +808,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
>   *	Add a destination into an existing service
>   */
>  static int
> -ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
> +ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  {
>  	struct ip_vs_dest *dest;
> -	__be32 daddr = udest->addr;
> +	union nf_inet_addr daddr;
>  	__be16 dport = udest->port;
>  	int ret;
>  
> @@ -827,10 +828,12 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
>  		return -ERANGE;
>  	}
>  
> +	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
> +
>  	/*
>  	 * Check if the dest already exists in the list
>  	 */
> -	dest = ip_vs_lookup_dest(svc, daddr, dport);
> +	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
>  	if (dest != NULL) {
>  		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
>  		return -EEXIST;
> @@ -840,7 +843,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
>  	 * Check if the dest already exists in the trash and
>  	 * is from the same service
>  	 */
> -	dest = ip_vs_trash_get_dest(svc, daddr, dport);
> +	dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
>  	if (dest != NULL) {
>  		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
>  			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
> @@ -915,10 +918,10 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
>   *	Edit a destination in the given service
>   */
>  static int
> -ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
> +ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  {
>  	struct ip_vs_dest *dest;
> -	__be32 daddr = udest->addr;
> +	union nf_inet_addr daddr;
>  	__be16 dport = udest->port;
>  
>  	EnterFunction(2);
> @@ -934,10 +937,12 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
>  		return -ERANGE;
>  	}
>  
> +	ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
> +
>  	/*
>  	 *  Lookup the destination list
>  	 */
> -	dest = ip_vs_lookup_dest(svc, daddr, dport);
> +	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
>  	if (dest == NULL) {
>  		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
>  		return -ENOENT;
> @@ -1028,15 +1033,15 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
>   *	Delete a destination server in the given service
>   */
>  static int
> -ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
> +ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  {
>  	struct ip_vs_dest *dest;
> -	__be32 daddr = udest->addr;
>  	__be16 dport = udest->port;
>  
>  	EnterFunction(2);
>  
> -	dest = ip_vs_lookup_dest(svc, daddr, dport);
> +	dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
> +
>  	if (dest == NULL) {
>  		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
>  		return -ENOENT;
> @@ -1071,7 +1076,8 @@ ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
>   *	Add a service into the service hash table
>   */
>  static int
> -ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
> +ip_vs_add_service(struct ip_vs_service_user_kern *u,
> +		  struct ip_vs_service **svc_p)
>  {
>  	int ret = 0;
>  	struct ip_vs_scheduler *sched = NULL;
> @@ -1100,8 +1106,9 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
>  	atomic_set(&svc->usecnt, 1);
>  	atomic_set(&svc->refcnt, 0);
>  
> +	svc->af = u->af;
>  	svc->protocol = u->protocol;
> -	svc->addr.ip = u->addr;
> +	ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
>  	svc->port = u->port;
>  	svc->fwmark = u->fwmark;
>  	svc->flags = u->flags;
> @@ -1160,7 +1167,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
>   *	Edit a service and bind it with a new scheduler
>   */
>  static int
> -ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u)
> +ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
>  {
>  	struct ip_vs_scheduler *sched, *old_sched;
>  	int ret = 0;
> @@ -1904,14 +1911,44 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
>  	[SET_CMDID(IP_VS_SO_SET_ZERO)]		= SERVICE_ARG_LEN,
>  };
>  
> +static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
> +				  struct ip_vs_service_user *usvc_compat)
> +{
> +	usvc->af		= AF_INET;
> +	usvc->protocol		= usvc_compat->protocol;
> +	usvc->addr.ip		= usvc_compat->addr;
> +	usvc->port		= usvc_compat->port;
> +	usvc->fwmark		= usvc_compat->fwmark;
> +
> +	/* Deep copy of sched_name is not needed here */
> +	usvc->sched_name	= usvc_compat->sched_name;
> +
> +	usvc->flags		= usvc_compat->flags;
> +	usvc->timeout		= usvc_compat->timeout;
> +	usvc->netmask		= usvc_compat->netmask;
> +}
> +
> +static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
> +				   struct ip_vs_dest_user *udest_compat)
> +{
> +	udest->addr.ip		= udest_compat->addr;
> +	udest->port		= udest_compat->port;
> +	udest->conn_flags	= udest_compat->conn_flags;
> +	udest->weight		= udest_compat->weight;
> +	udest->u_threshold	= udest_compat->u_threshold;
> +	udest->l_threshold	= udest_compat->l_threshold;
> +}
> +
>  static int
>  do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
>  {
>  	int ret;
>  	unsigned char arg[MAX_ARG_LEN];
> -	struct ip_vs_service_user *usvc;
> +	struct ip_vs_service_user *usvc_compat;
> +	struct ip_vs_service_user_kern usvc;
>  	struct ip_vs_service *svc;
> -	struct ip_vs_dest_user *udest;
> +	struct ip_vs_dest_user *udest_compat;
> +	struct ip_vs_dest_user_kern udest;
>  
>  	if (!capable(CAP_NET_ADMIN))
>  		return -EPERM;
> @@ -1951,35 +1988,40 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
>  		goto out_unlock;
>  	}
>  
> -	usvc = (struct ip_vs_service_user *)arg;
> -	udest = (struct ip_vs_dest_user *)(usvc + 1);
> +	usvc_compat = (struct ip_vs_service_user *)arg;
> +	udest_compat = (struct ip_vs_dest_user *)(usvc_compat + 1);
> +
> +	/* We only use the new structs internally, so copy userspace compat
> +	 * structs to extended internal versions */
> +	ip_vs_copy_usvc_compat(&usvc, usvc_compat);
> +	ip_vs_copy_udest_compat(&udest, udest_compat);
>  
>  	if (cmd == IP_VS_SO_SET_ZERO) {
>  		/* if no service address is set, zero counters in all */
> -		if (!usvc->fwmark && !usvc->addr && !usvc->port) {
> +		if (!usvc.fwmark && !usvc.addr.ip && !usvc.port) {
>  			ret = ip_vs_zero_all();
>  			goto out_unlock;
>  		}
>  	}
>  
>  	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
> -	if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) {
> +	if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) {
>  		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
> -			  usvc->protocol, NIPQUAD(usvc->addr),
> -			  ntohs(usvc->port), usvc->sched_name);
> +			  usvc.protocol, NIPQUAD(usvc.addr.ip),
> +			  ntohs(usvc.port), usvc.sched_name);
>  		ret = -EFAULT;
>  		goto out_unlock;
>  	}
>  
>  	/* Lookup the exact service by <protocol, addr, port> or fwmark */
> -	if (usvc->fwmark == 0)
> -		svc = __ip_vs_service_get(usvc->protocol,
> -					  usvc->addr, usvc->port);
> +	if (usvc.fwmark == 0)
> +		svc = __ip_vs_service_get(usvc.protocol,
> +					  usvc.addr.ip, usvc.port);
>  	else
> -		svc = __ip_vs_svc_fwm_get(usvc->fwmark);
> +		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
>  
>  	if (cmd != IP_VS_SO_SET_ADD
> -	    && (svc == NULL || svc->protocol != usvc->protocol)) {
> +	    && (svc == NULL || svc->protocol != usvc.protocol)) {
>  		ret = -ESRCH;
>  		goto out_unlock;
>  	}
> @@ -1989,10 +2031,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
>  		if (svc != NULL)
>  			ret = -EEXIST;
>  		else
> -			ret = ip_vs_add_service(usvc, &svc);
> +			ret = ip_vs_add_service(&usvc, &svc);
>  		break;
>  	case IP_VS_SO_SET_EDIT:
> -		ret = ip_vs_edit_service(svc, usvc);
> +		ret = ip_vs_edit_service(svc, &usvc);
>  		break;
>  	case IP_VS_SO_SET_DEL:
>  		ret = ip_vs_del_service(svc);
> @@ -2003,13 +2045,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
>  		ret = ip_vs_zero_service(svc);
>  		break;
>  	case IP_VS_SO_SET_ADDDEST:
> -		ret = ip_vs_add_dest(svc, udest);
> +		ret = ip_vs_add_dest(svc, &udest);
>  		break;
>  	case IP_VS_SO_SET_EDITDEST:
> -		ret = ip_vs_edit_dest(svc, udest);
> +		ret = ip_vs_edit_dest(svc, &udest);
>  		break;
>  	case IP_VS_SO_SET_DELDEST:
> -		ret = ip_vs_del_dest(svc, udest);
> +		ret = ip_vs_del_dest(svc, &udest);
>  		break;
>  	default:
>  		ret = -EINVAL;
> @@ -2516,7 +2558,7 @@ nla_put_failure:
>  	return skb->len;
>  }
>  
> -static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
> +static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
>  				    struct nlattr *nla, int full_entry)
>  {
>  	struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
> @@ -2536,6 +2578,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
>  	if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
>  		return -EINVAL;
>  
> +	usvc->af = nla_get_u16(nla_af);
>  	/* For now, only support IPv4 */
>  	if (nla_get_u16(nla_af) != AF_INET)
>  		return -EAFNOSUPPORT;
> @@ -2571,7 +2614,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
>  		if (usvc->fwmark)
>  			svc = __ip_vs_svc_fwm_get(usvc->fwmark);
>  		else
> -			svc = __ip_vs_service_get(usvc->protocol, usvc->addr,
> +			svc = __ip_vs_service_get(usvc->protocol, usvc->addr.ip,
>  						  usvc->port);
>  		if (svc) {
>  			usvc->flags = svc->flags;
> @@ -2582,9 +2625,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
>  		/* set new flags from userland */
>  		usvc->flags = (usvc->flags & ~flags.mask) |
>  			      (flags.flags & flags.mask);
> -
> -		strlcpy(usvc->sched_name, nla_data(nla_sched),
> -			sizeof(usvc->sched_name));
> +		usvc->sched_name = nla_data(nla_sched);
>  		usvc->timeout = nla_get_u32(nla_timeout);
>  		usvc->netmask = nla_get_u32(nla_netmask);
>  	}
> @@ -2594,7 +2635,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
>  
>  static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
>  {
> -	struct ip_vs_service_user usvc;
> +	struct ip_vs_service_user_kern usvc;
>  	int ret;
>  
>  	ret = ip_vs_genl_parse_service(&usvc, nla, 0);
> @@ -2604,7 +2645,7 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
>  	if (usvc.fwmark)
>  		return __ip_vs_svc_fwm_get(usvc.fwmark);
>  	else
> -		return __ip_vs_service_get(usvc.protocol, usvc.addr,
> +		return __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
>  					   usvc.port);
>  }
>  
> @@ -2704,7 +2745,7 @@ out_err:
>  	return skb->len;
>  }
>  
> -static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
> +static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
>  				 struct nlattr *nla, int full_entry)
>  {
>  	struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
> @@ -2860,8 +2901,8 @@ static int ip_vs_genl_set_config(struct nlattr **attrs)
>  static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
>  {
>  	struct ip_vs_service *svc = NULL;
> -	struct ip_vs_service_user usvc;
> -	struct ip_vs_dest_user udest;
> +	struct ip_vs_service_user_kern usvc;
> +	struct ip_vs_dest_user_kern udest;
>  	int ret = 0, cmd;
>  	int need_full_svc = 0, need_full_dest = 0;
>  
> @@ -2913,7 +2954,8 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
>  
>  	/* Lookup the exact service by <protocol, addr, port> or fwmark */
>  	if (usvc.fwmark == 0)
> -		svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port);
> +		svc = __ip_vs_service_get(usvc.protocol, usvc.addr.ip,
> +					  usvc.port);
>  	else
>  		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
>  
> -- 
> 1.5.4.5

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses
  2008-09-01 12:55 ` [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
  2008-09-02  5:23   ` Simon Horman
@ 2008-09-02  6:08   ` Simon Horman
  1 sibling, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  6:08 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:55:59PM +0200, Julius Volz wrote:
> Introduce new 'af' fields into IPVS data structures for specifying an
> entry's address family. Convert IP addresses to be of type union
> nf_inet_addr.

Could you please run this patch through ./scripts/checkpatch.pl,
it has flaged some whitespace issues for me.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions
  2008-09-01 12:56 ` [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions Julius Volz
@ 2008-09-02  6:26   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  6:26 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:06PM +0200, Julius Volz wrote:
> Add 'af' arguments to conn_schedule(), conn_in_get(), conn_out_get() and
> csum_check() function pointers in struct ip_vs_protocol. Extend the
> respective functions for TCP, UDP, AH and ESP and adjust the callers.
> 
> The changes in the callers need to be somewhat extensive, since they now
> need to pass a filled out struct ip_vs_iphdr * to the modified functions
> instead of a struct iphdr *.

Hi Julius,

./scripts/checkpatch.pl has flagged the following problems.
Could you take a look into the whitespace ones? I'm not
so concerned about the assignment one as it is
an existing problem - though if you want to fix it here and elsewhere,
thats fine too :-)

ERROR: code indent should use tabs where possible
#307: FILE: net/ipv4/ipvs/ip_vs_proto_ah_esp.c:43:
+^I           const struct ip_vs_iphdr *iph, unsigned int proto_off,$

ERROR: code indent should use tabs where possible
#308: FILE: net/ipv4/ipvs/ip_vs_proto_ah_esp.c:44:
+^I           int inverse)$

ERROR: code indent should use tabs where possible
#357: FILE: net/ipv4/ipvs/ip_vs_proto_ah_esp.c:82:
+^I            const struct ip_vs_iphdr *iph,$

ERROR: code indent should use tabs where possible
#359: FILE: net/ipv4/ipvs/ip_vs_proto_ah_esp.c:84:
+^I            int inverse)$

ERROR: do not use assignment in if condition
#654: FILE: net/ipv4/ipvs/ip_vs_proto_udp.c:94:
+	if ((svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,

total: 5 errors, 0 warnings, 624 lines checked

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections
  2008-09-01 12:56 ` [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections Julius Volz
@ 2008-09-02  6:47   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  6:47 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:09PM +0200, Julius Volz wrote:
> Extend functions for getting/creating connections and connection
> templates for IPv6 support and fix the callers.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>

./scripts/checkpatch.pl has flagged the following problems.
I realise that the last one is not new, but could you fix it anyway?

WARNING: line over 80 characters
#177: FILE: net/ipv4/ipvs/ip_vs_conn.c:236:
+		cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr, d_port);

WARNING: line over 80 characters
#549: FILE: net/ipv4/ipvs/ip_vs_ftp.c:175:
+			  NIPQUAD(from.ip), ntohs(port), NIPQUAD(cp->caddr.ip), 0);

ERROR: space required after that ',' (ctx:VxV)
#578: FILE: net/ipv4/ipvs/ip_vs_ftp.c:201:
+		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from.ip),
 		           ^

total: 1 errors, 2 warnings, 690 lines checked

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions
  2008-09-01 12:56 ` [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions Julius Volz
@ 2008-09-02  7:32   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  7:32 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:11PM +0200, Julius Volz wrote:
> Add xmit functions for IPv6. Also add the already needed __ip_vs_get_out_rt_v6()
> to ip_vs_core.c. Bind the new xmit functions to v6 connections.

./scripts/checkpatch.pl seems unhappy about a number of things here.
I relise this is because you are following the existing style
in the file. But in this new code it might make sense
to follow checkpatch.pl's advice.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6
  2008-09-01 12:56 ` [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6 Julius Volz
@ 2008-09-02  7:40   ` Simon Horman
  2008-09-02 13:34     ` Julius Volz
  0 siblings, 1 reply; 46+ messages in thread
From: Simon Horman @ 2008-09-02  7:40 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:13PM +0200, Julius Volz wrote:
> Add Netfilter hook functions or modify existing ones, if possible, to
> process IPv6 packets. Some support functions are also added/modified for
> this. ip_vs_nat_icmp_v6() was already added in the patch that added the v6
> xmit functions, as it is called from one of them.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>

Please run checkpatch.pl over this patch.

>  1 files changed, 326 insertions(+), 36 deletions(-)
> 
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 8bfd7c2..0bf871c 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -39,6 +39,11 @@
>  #include <linux/netfilter.h>
>  #include <linux/netfilter_ipv4.h>
>  
> +#ifdef CONFIG_IP_VS_IPV6
> +#include <net/ipv6.h>
> +#include <linux/netfilter_ipv6.h>
> +#endif
> +
>  #include <net/ip_vs.h>
>  
>  
> @@ -60,6 +65,7 @@ EXPORT_SYMBOL(ip_vs_get_debug_level);
>  
>  /* ID used in ICMP lookups */
>  #define icmp_id(icmph)          (((icmph)->un).echo.id)
> +#define icmpv6_id(icmph)        (icmph->icmp6_dataun.u_echo.identifier)

Should this be ((icmph)->icmp6_dataun.u_echo.identifier) ?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions
  2008-09-01 12:56 ` [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions Julius Volz
@ 2008-09-02  7:46   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  7:46 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:14PM +0200, Julius Volz wrote:
> Convert functions for looking up destinations (real servers) to support
> IPv6 services/dests.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>
> 
>  5 files changed, 66 insertions(+), 37 deletions(-)
> 
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index a7eda08..c163c18 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -804,14 +804,16 @@ static inline void ip_vs_service_put(struct ip_vs_service *svc)
>  }
>  
>  extern struct ip_vs_dest *
> -ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
> +ip_vs_lookup_real_service(int af, __u16 protocol,
> +			  const union nf_inet_addr *daddr, __be16 dport);
> +
>  extern int ip_vs_use_count_inc(void);
>  extern void ip_vs_use_count_dec(void);
>  extern int ip_vs_control_init(void);
>  extern void ip_vs_control_cleanup(void);
>  extern struct ip_vs_dest *
> -ip_vs_find_dest(__be32 daddr, __be16 dport,
> -		 __be32 vaddr, __be16 vport, __u16 protocol);
> +ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport,
> +		const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol);
>  extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
>  
>  
> diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
> index 814d416..2f5c4d8 100644
> --- a/net/ipv4/ipvs/ip_vs_conn.c
> +++ b/net/ipv4/ipvs/ip_vs_conn.c
> @@ -490,8 +490,9 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
>  	struct ip_vs_dest *dest;
>  
>  	if ((cp) && (!cp->dest)) {
> -		dest = ip_vs_find_dest(cp->daddr.ip, cp->dport,
> -				       cp->vaddr.ip, cp->vport, cp->protocol);
> +		dest = ip_vs_find_dest(cp->af, &cp->daddr, cp->dport,
> +				       &cp->vaddr, cp->vport,
> +				       cp->protocol);
>  		ip_vs_bind_dest(cp, dest);
>  		return dest;
>  	} else
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 0bf871c..2725b93 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -956,8 +956,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
>  						  sizeof(_ports), _ports);
>  			if (pptr == NULL)
>  				return NF_ACCEPT;	/* Not for me */
> -			if (ip_vs_lookup_real_service(iph.protocol,
> -						      iph.saddr.ip,
> +			if (ip_vs_lookup_real_service(af, iph.protocol,
> +						      &iph.saddr,
>  						      pptr[0])) {
>  				/*
>  				 * Notify the real server: there is no
> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> index 151d368..3dae1d9 100644
> --- a/net/ipv4/ipvs/ip_vs_ctl.c
> +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> @@ -492,11 +492,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
>  /*
>   *	Returns hash value for real service
>   */
> -static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
> +static __inline__ unsigned ip_vs_rs_hashkey(int af,
> +					    const union nf_inet_addr *addr,
> +					    __be16 port)
>  {
>  	register unsigned porth = ntohs(port);
> +	__be32 addr_fold = addr->ip;
> +
> +#ifdef CONFIG_IP_VS_IPV6
> +	if (af == AF_INET6)
> +		addr_fold = addr->ip6[0]^addr->ip6[1]^
> +			    addr->ip6[2]^addr->ip6[3];
> +#endif
>  
> -	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
> +	return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
>  		& IP_VS_RTAB_MASK;
>  }
>  
> @@ -516,7 +525,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
>  	 *	Hash by proto,addr,port,
>  	 *	which are the parameters of the real service.
>  	 */
> -	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
> +	hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
> +
>  	list_add(&dest->d_list, &ip_vs_rtable[hash]);
>  
>  	return 1;
> @@ -543,7 +553,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
>   *	Lookup real service by <proto,addr,port> in the real service table.
>   */
>  struct ip_vs_dest *
> -ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
> +ip_vs_lookup_real_service(int af, __u16 protocol,
> +			  const union nf_inet_addr *daddr,
> +			  __be16 dport)
>  {
>  	unsigned hash;
>  	struct ip_vs_dest *dest;
> @@ -552,11 +564,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
>  	 *	Check for "full" addressed entries
>  	 *	Return the first found entry
>  	 */
> -	hash = ip_vs_rs_hashkey(daddr, dport);
> +	hash = ip_vs_rs_hashkey(af, daddr, dport);
>  
>  	read_lock(&__ip_vs_rs_lock);
>  	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
> -		if ((dest->addr.ip == daddr)
> +		if ((dest->af == af)
> +		    && ip_vs_addr_equal(af, &dest->addr, daddr)
>  		    && (dest->port == dport)
>  		    && ((dest->protocol == protocol) ||
>  			dest->vfwmark)) {
> @@ -574,7 +587,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
>   *	Lookup destination by {addr,port} in the given service
>   */
>  static struct ip_vs_dest *
> -ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
> +ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
> +		  __be16 dport)
>  {
>  	struct ip_vs_dest *dest;
>  
> @@ -582,7 +596,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  	 * Find the destination for the given service
>  	 */
>  	list_for_each_entry(dest, &svc->destinations, n_list) {
> -		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
> +		if ((dest->af == svc->af)
> +		    && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
> +		    && (dest->port == dport)) {
>  			/* HIT */
>  			return dest;
>  		}
> @@ -601,14 +617,14 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>   * ip_vs_lookup_real_service() looked promissing, but
>   * seems not working as expected.
>   */
> -struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
> -				    __be32 vaddr, __be16 vport, __u16 protocol)
> +struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
> +				   __be16 dport, const union nf_inet_addr *vaddr,

Please split the line above.

> +				   __be16 vport, __u16 protocol)
>  {
>  	struct ip_vs_dest *dest;
>  	struct ip_vs_service *svc;
> -	union nf_inet_addr _vaddr = { .ip = vaddr };
>  
> -	svc = ip_vs_service_get(AF_INET, 0, protocol, &_vaddr, vport);
> +	svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
>  	if (!svc)
>  		return NULL;
>  	dest = ip_vs_lookup_dest(svc, daddr, dport);
> @@ -629,7 +645,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
>   *  scheduling.
>   */
>  static struct ip_vs_dest *
> -ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
> +ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
> +		     __be16 dport)
>  {
>  	struct ip_vs_dest *dest, *nxt;
>  
> @@ -637,17 +654,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  	 * Find the destination in trash
>  	 */
>  	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
> -		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
> -			  "dest->refcnt=%d\n",
> -			  dest->vfwmark,
> -			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
> -			  atomic_read(&dest->refcnt));
> -		if (dest->addr.ip == daddr &&
> +		IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
> +			      "dest->refcnt=%d\n",
> +			      dest->vfwmark,
> +			      IP_VS_DBG_ADDR(svc->af, &dest->addr),
> +			      ntohs(dest->port),
> +			      atomic_read(&dest->refcnt));
> +		if (dest->af == svc->af &&
> +		    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
>  		    dest->port == dport &&
>  		    dest->vfwmark == svc->fwmark &&
>  		    dest->protocol == svc->protocol &&
>  		    (svc->fwmark ||
> -		     (dest->vaddr.ip == svc->addr.ip &&
> +		     (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
>  		      dest->vport == svc->port))) {
>  			/* HIT */
>  			return dest;
> @@ -657,10 +676,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
>  		 * Try to purge the destination from trash if not referenced
>  		 */
>  		if (atomic_read(&dest->refcnt) == 1) {
> -			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
> -				  "from trash\n",
> -				  dest->vfwmark,
> -				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
> +			IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
> +				      "from trash\n",
> +				      dest->vfwmark,
> +				      IP_VS_DBG_ADDR(svc->af, &dest->addr),
> +				      ntohs(dest->port));
>  			list_del(&dest->n_list);
>  			ip_vs_dst_reset(dest);
>  			__ip_vs_unbind_svc(dest);
> @@ -847,7 +867,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  	/*
>  	 * Check if the dest already exists in the list
>  	 */
> -	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
> +	dest = ip_vs_lookup_dest(svc, &daddr, dport);
> +
>  	if (dest != NULL) {
>  		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
>  		return -EEXIST;
> @@ -857,7 +878,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  	 * Check if the dest already exists in the trash and
>  	 * is from the same service
>  	 */
> -	dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
> +	dest = ip_vs_trash_get_dest(svc, &daddr, dport);
> +
>  	if (dest != NULL) {
>  		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
>  			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
> @@ -956,7 +978,8 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  	/*
>  	 *  Lookup the destination list
>  	 */
> -	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
> +	dest = ip_vs_lookup_dest(svc, &daddr, dport);
> +
>  	if (dest == NULL) {
>  		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
>  		return -ENOENT;
> @@ -1054,7 +1077,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
>  
>  	EnterFunction(2);
>  
> -	dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
> +	dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
>  
>  	if (dest == NULL) {
>  		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
> diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
> index 3ce1093..40647ed 100644
> --- a/net/ipv4/ipvs/ip_vs_sync.c
> +++ b/net/ipv4/ipvs/ip_vs_sync.c
> @@ -383,8 +383,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
>  			 * If it is not found the connection will remain unbound
>  			 * but still handled.
>  			 */
> -			dest = ip_vs_find_dest(s->daddr, s->dport,
> -					       s->vaddr, s->vport,
> +			dest = ip_vs_find_dest(AF_INET,
> +					       (union nf_inet_addr *)&s->daddr,
> +					       s->dport,
> +					       (union nf_inet_addr *)&s->vaddr,
> +					       s->vport,
>  					       s->protocol);
>  			/*  Set the approprite ativity flag */
>  			if (s->protocol == IPPROTO_TCP) {
> -- 
> 1.5.4.5

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output
  2008-09-01 12:56 ` [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output Julius Volz
@ 2008-09-02  7:49   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  7:49 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:15PM +0200, Julius Volz wrote:
> From: Vince Busam <vbusam@google.com>
> 
> Correctly output IPv6 connection/service/dest entries in procfs files.

Hi Julius,

Please run checkpatch.pl over this patch.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local
  2008-09-01 12:56 ` [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local Julius Volz
@ 2008-09-02  7:57   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  7:57 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:18PM +0200, Julius Volz wrote:
> From: Vince Busam <vbusam@google.com>
> 
> Add __ip_vs_addr_is_local_v6() to find out if an IPv6 address belongs to a
> local interface. Use this function to decide whether to set the
> IP_VS_CONN_F_LOCALNODE flag for IPv6 destinations.

Hi Vince,

could you please fix the following minor problems that were flagged
by checkpatch.pl ?

ERROR: open brace '{' following function declarations go on the next line
#78: FILE: net/ipv4/ipvs/ip_vs_ctl.c:100:
+static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) {

ERROR: do not use assignment in if condition
#87: FILE: net/ipv4/ipvs/ip_vs_ctl.c:109:
+	if ((rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl)))

> Signed-off-by: Vince Busam <vbusam@google.com>
> 
>  1 files changed, 46 insertions(+), 7 deletions(-)
> 
> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> index fe17504..3ce2873 100644
> --- a/net/ipv4/ipvs/ip_vs_ctl.c
> +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> @@ -35,6 +35,10 @@
>  
>  #include <net/net_namespace.h>
>  #include <net/ip.h>
> +#ifdef CONFIG_IP_VS_IPV6
> +#include <net/ipv6.h>
> +#include <net/ip6_route.h>
> +#endif
>  #include <net/route.h>
>  #include <net/sock.h>
>  #include <net/genetlink.h>
> @@ -91,6 +95,23 @@ int ip_vs_get_debug_level(void)
>  }
>  #endif
>  
> +#ifdef CONFIG_IP_VS_IPV6
> +/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
> +static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) {
> +	struct rt6_info *rt;
> +	struct flowi fl = {
> +		.oif = 0,
> +		.nl_u = {
> +			.ip6_u = {
> +				.daddr = *addr,
> +				.saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
> +	};
> +	if ((rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl)))
> +		if (rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK))
> +			return 1;
> +	return 0;
> +}
> +#endif
>  /*
>   *	update_defense_level is called from keventd and from sysctl,
>   *	so it needs to protect itself from softirqs
> @@ -750,10 +771,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
>  	conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
>  
>  	/* check if local node and update the flags */
> -	if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
> -		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
> -			| IP_VS_CONN_F_LOCALNODE;
> -	}
> +#ifdef CONFIG_IP_VS_IPV6
> +	if (svc->af == AF_INET6) {
> +		if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
> +			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
> +				| IP_VS_CONN_F_LOCALNODE;
> +		}
> +	} else
> +#endif
> +		if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
> +			conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
> +				| IP_VS_CONN_F_LOCALNODE;
> +		}
>  
>  	/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
>  	if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
> @@ -802,9 +831,19 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
>  
>  	EnterFunction(2);
>  
> -	atype = inet_addr_type(&init_net, udest->addr.ip);
> -	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
> -		return -EINVAL;
> +#ifdef CONFIG_IP_VS_IPV6
> +	if (svc->af == AF_INET6) {
> +		atype = ipv6_addr_type(&udest->addr.in6);
> +		if (!(atype & IPV6_ADDR_UNICAST) &&
> +			!__ip_vs_addr_is_local_v6(&udest->addr.in6))
> +			return -EINVAL;
> +	} else
> +#endif
> +	{
> +		atype = inet_addr_type(&init_net, udest->addr.ip);
> +		if (atype != RTN_LOCAL && atype != RTN_UNICAST)
> +			return -EINVAL;
> +	}
>  
>  	dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
>  	if (dest == NULL) {
> -- 
> 1.5.4.5

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros
  2008-09-01 12:56 ` [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros Julius Volz
@ 2008-09-02  8:00   ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-02  8:00 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:19PM +0200, Julius Volz wrote:
> Adjust various debug outputs to use the new *_BUF macro variants for
> correct output of v4/v6 addresses.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>

Hi Julius,

I realise that these are existing style problems not new ones, but
could you run this patch through checkpatch.pl and clean things up
a little?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS
  2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
                   ` (24 preceding siblings ...)
  2008-09-01 12:56 ` [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments Julius Volz
@ 2008-09-02  8:18 ` Simon Horman
  2008-09-02  9:22   ` Julius Volz
  25 siblings, 1 reply; 46+ messages in thread
From: Simon Horman @ 2008-09-02  8:18 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:55:57PM +0200, Julius Volz wrote:
> I now managed to rework the IPVS IPv6 patches in a way that the kernel
> builds after each patch in the series. Sometimes, this adds some
> ugliness in the form of temporary constructs which are introduced in one
> patch and deleted in the next ones. I've also integrated other small bug
> fixes and cleanups from comments on the mailing lists.

Thanks, I appreciate that. I think that these patches are starting
to look quite nice. I've posted some coments (all relating to style I
think) to some of the patches. Nothing else has caught my eye so far.

> Note: these patches are not based on net-2.6 anymore, but on lvs-2.6:

I've verified that these patches apply against the lvs-next-2.6 branch of
of the lvs-2.6 tree. Which means they should also apply against Dave's
net-next-2.6 tree (net-next-2.6 and lvs-next-2.6 are currently converged).
Which would seem to be the most likely target for these changes at this
time.

> git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-2.6.git
> 
> - Full kernel patch in one file:
>   http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6_v2.patch
> 
> While not all IPv6 features are working or tested, existing IPv4 features
> should still work as before. However, to use any of the new features, you
> will need a new ipvsadm with support for genetlink and IPv6:

I'm comfortable with merging things in that state.

It seems quite reasonable to add IPv6 features in an iterative
manner so long as IPv4 keeps working.

>   http://sixpak.org/vince/google/ipvsadm/
>   (by Vince Busam)
> 
> To enable IPv6 support in IPVS, set CONFIG_IP_VS_IPV6=y.
> 
> Short overview:
> 
> What works with IPv6:
> - forwarding mechanisms: NAT, DR, maybe Tunnel (not fully tested yet)
> - protocols: TCP, UDP, ESP, AH (last two not tested)
> - manipulation and inspection of both IPv4 and IPv6 entries with ipvsadm
> - 6 out of 10 schedulers
> 
> What is not supported with IPv6:
> - handling fragmentation or other extension headers
> - FTP application helper (can be loaded, but only operates on v4)
> - sync daemon (can be started, but only operates on v4)
> - probably some incorrect handling of ICMPv6 or other corner cases
> 
> Since fragmentation and extension headers should not occur very often,
> things should "mostly" work. I tested HTTP and DNS over NAT and DR
> with various supported schedulers without encountering any problems.
> But we didn't test any exotic situations. Also, there are some TODOs
> in the code for things that haven't been tested or implemented yet.
> 
> Thanks for any comments!
> 
> Julius

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS
  2008-09-02  8:18 ` [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Simon Horman
@ 2008-09-02  9:22   ` Julius Volz
  0 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-02  9:22 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam

On Tue, Sep 2, 2008 at 10:18 AM, Simon Horman <horms@verge.net.au> wrote:
> On Mon, Sep 01, 2008 at 02:55:57PM +0200, Julius Volz wrote:
>> I now managed to rework the IPVS IPv6 patches in a way that the kernel
>> builds after each patch in the series. Sometimes, this adds some
>> ugliness in the form of temporary constructs which are introduced in one
>> patch and deleted in the next ones. I've also integrated other small bug
>> fixes and cleanups from comments on the mailing lists.
>
> Thanks, I appreciate that. I think that these patches are starting
> to look quite nice. I've posted some coments (all relating to style I
> think) to some of the patches. Nothing else has caught my eye so far.

Great, thanks! I will now fix all the style issues you pointed out in
the other mails!

>> Note: these patches are not based on net-2.6 anymore, but on lvs-2.6:
>
> I've verified that these patches apply against the lvs-next-2.6 branch of
> of the lvs-2.6 tree. Which means they should also apply against Dave's
> net-next-2.6 tree (net-next-2.6 and lvs-next-2.6 are currently converged).
> Which would seem to be the most likely target for these changes at this
> time.

That would be awesome!

>> git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-2.6.git
>>
>> - Full kernel patch in one file:
>>   http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6_v2.patch
>>
>> While not all IPv6 features are working or tested, existing IPv4 features
>> should still work as before. However, to use any of the new features, you
>> will need a new ipvsadm with support for genetlink and IPv6:
>
> I'm comfortable with merging things in that state.
>
> It seems quite reasonable to add IPv6 features in an iterative
> manner so long as IPv4 keeps working.

Yes, people should test especially if there are any problems with the
existing IPv4 features...

Julius

-- 
Julius Volz - Corporate Operations - SysOps

Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments
  2008-09-02  2:25   ` Stephen Hemminger
@ 2008-09-02  9:22     ` Julius Volz
  0 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-02  9:22 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, lvs-devel, horms, kaber, vbusam

On Tue, Sep 2, 2008 at 4:25 AM, Stephen Hemminger <shemminger@vyatta.com> wrote:
> On Mon,  1 Sep 2008 14:56:22 +0200
> Julius Volz <juliusv@google.com> wrote:
>
>> Add notes about the IPv6 changes to the relevant files' header comments.
>>
>> Signed-off-by: Julius Volz <juliusv@google.com>
>
> No. This is no longer necessary.
> Git changelog is sufficient

Ok!

-- 
Julius Volz - Corporate Operations - SysOps

Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6
  2008-09-02  7:40   ` Simon Horman
@ 2008-09-02 13:34     ` Julius Volz
  0 siblings, 0 replies; 46+ messages in thread
From: Julius Volz @ 2008-09-02 13:34 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam

On Tue, Sep 2, 2008 at 9:40 AM, Simon Horman <horms@verge.net.au> wrote:
> On Mon, Sep 01, 2008 at 02:56:13PM +0200, Julius Volz wrote:
>> Add Netfilter hook functions or modify existing ones, if possible, to
>> process IPv6 packets. Some support functions are also added/modified for
>> this. ip_vs_nat_icmp_v6() was already added in the patch that added the v6
>> xmit functions, as it is called from one of them.
>>
>> Signed-off-by: Julius Volz <juliusv@google.com>
>
> Please run checkpatch.pl over this patch.
>
>>  1 files changed, 326 insertions(+), 36 deletions(-)
>>
>> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
>> index 8bfd7c2..0bf871c 100644
>> --- a/net/ipv4/ipvs/ip_vs_core.c
>> +++ b/net/ipv4/ipvs/ip_vs_core.c
>> @@ -39,6 +39,11 @@
>>  #include <linux/netfilter.h>
>>  #include <linux/netfilter_ipv4.h>
>>
>> +#ifdef CONFIG_IP_VS_IPV6
>> +#include <net/ipv6.h>
>> +#include <linux/netfilter_ipv6.h>
>> +#endif
>> +
>>  #include <net/ip_vs.h>
>>
>>
>> @@ -60,6 +65,7 @@ EXPORT_SYMBOL(ip_vs_get_debug_level);
>>
>>  /* ID used in ICMP lookups */
>>  #define icmp_id(icmph)          (((icmph)->un).echo.id)
>> +#define icmpv6_id(icmph)        (icmph->icmp6_dataun.u_echo.identifier)
>
> Should this be ((icmph)->icmp6_dataun.u_echo.identifier) ?

Ah yeah, that is safer, thanks!

-- 
Julius Volz - Corporate Operations - SysOps

Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions
  2008-09-01 12:56 ` [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions Julius Volz
@ 2008-09-02 22:28   ` Simon Horman
  2008-09-03  8:43     ` Julius Volz
  0 siblings, 1 reply; 46+ messages in thread
From: Simon Horman @ 2008-09-02 22:28 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Mon, Sep 01, 2008 at 02:56:10PM +0200, Julius Volz wrote:
> Add IPv6 support to IP_VS_XMIT() and to the xmit routing cache, introducing
> a new function __ip_vs_get_out_rt_v6().

Hi,

sorry, I missed this one yesteray. Could you run checkpatch.pl over
this one also?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions
  2008-09-02 22:28   ` Simon Horman
@ 2008-09-03  8:43     ` Julius Volz
  2008-09-03  8:48       ` Simon Horman
  0 siblings, 1 reply; 46+ messages in thread
From: Julius Volz @ 2008-09-03  8:43 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Sep 3, 2008 at 12:28 AM, Simon Horman <horms@verge.net.au> wrote:
> On Mon, Sep 01, 2008 at 02:56:10PM +0200, Julius Volz wrote:
>> Add IPv6 support to IP_VS_XMIT() and to the xmit routing cache, introducing
>> a new function __ip_vs_get_out_rt_v6().
>
> Hi,
>
> sorry, I missed this one yesteray. Could you run checkpatch.pl over
> this one also?

Yes, already cleaned up in the latest posted version (I ran
checkpatch.pl over all patches yesterday).

Julius

-- 
Julius Volz - Corporate Operations - SysOps

Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions
  2008-09-03  8:43     ` Julius Volz
@ 2008-09-03  8:48       ` Simon Horman
  0 siblings, 0 replies; 46+ messages in thread
From: Simon Horman @ 2008-09-03  8:48 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Sep 03, 2008 at 10:43:13AM +0200, Julius Volz wrote:
> On Wed, Sep 3, 2008 at 12:28 AM, Simon Horman <horms@verge.net.au> wrote:
> > On Mon, Sep 01, 2008 at 02:56:10PM +0200, Julius Volz wrote:
> >> Add IPv6 support to IP_VS_XMIT() and to the xmit routing cache, introducing
> >> a new function __ip_vs_get_out_rt_v6().
> >
> > Hi,
> >
> > sorry, I missed this one yesteray. Could you run checkpatch.pl over
> > this one also?
> 
> Yes, already cleaned up in the latest posted version (I ran
> checkpatch.pl over all patches yesterday).

Thanks. Sorry for not checking my inbox before posting.

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2008-09-03  8:48 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-01 12:55 [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Julius Volz
2008-09-01 12:55 ` [PATCHv2 RFC 01/25] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
2008-09-01 12:55 ` [PATCHv2 RFC 02/25] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
2008-09-02  5:23   ` Simon Horman
2008-09-02  5:53     ` Simon Horman
2008-09-02  6:08   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 03/25] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 04/25] IPVS: Add debug macros for v4 and v6 address output Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 05/25] IPVS: Add internal versions of sockopt interface structs Julius Volz
2008-09-02  6:06   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 06/25] IPVS: Convert __ip_vs_svc_get() and __ip_vs_fwm_get() Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 07/25] IPVS: Add v6 support to ip_vs_service_get() Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 08/25] IPVS: Add IPv6 support flag to schedulers Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 09/25] IPVS: Add 'af' args to protocol handler functions Julius Volz
2008-09-02  6:26   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 10/25] IPVS: Add protocol debug functions for IPv6 Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 11/25] IPVS: Extend protocol DNAT/SNAT and state handlers Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 12/25] IPVS: Extend functions for getting/creating connections Julius Volz
2008-09-02  6:47   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 13/25] IPVS: Add IPv6 support to xmit() support functions Julius Volz
2008-09-02 22:28   ` Simon Horman
2008-09-03  8:43     ` Julius Volz
2008-09-03  8:48       ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 14/25] IPVS: Add and bind IPv6 xmit functions Julius Volz
2008-09-02  7:32   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 15/25] IPVS: Extend scheduling functions for IPv6 support Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 16/25] IPVS: Add/adjust Netfilter hook functions and helpers for v6 Julius Volz
2008-09-02  7:40   ` Simon Horman
2008-09-02 13:34     ` Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 17/25] IPVS: Convert real server lookup functions Julius Volz
2008-09-02  7:46   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 18/25] IPVS: Convert procfs files for IPv6 entry output Julius Volz
2008-09-02  7:49   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 19/25] IVPS: Disable sync daemon for IPv6 connections Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 20/25] IPVS: Turn off FTP application helper for IPv6 Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 21/25] IPVS: Add function to determine if IPv6 address is local Julius Volz
2008-09-02  7:57   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 22/25] IPVS: Adjust various debug outputs to use new macros Julius Volz
2008-09-02  8:00   ` Simon Horman
2008-09-01 12:56 ` [PATCHv2 RFC 23/25] IPVS: Activate IPv6 Netfilter hooks Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 24/25] IPVS: Allow adding IPv6 services from userspace Julius Volz
2008-09-01 12:56 ` [PATCHv2 RFC 25/25] IPVS: Add changelog notes to header comments Julius Volz
2008-09-02  2:25   ` Stephen Hemminger
2008-09-02  9:22     ` Julius Volz
2008-09-02  8:18 ` [PATCHv2 RFC 00/00] Add first IPv6 support to IPVS Simon Horman
2008-09-02  9:22   ` Julius Volz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).