netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
@ 2008-08-20 16:15 Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
                   ` (24 more replies)
  0 siblings, 25 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam

Hi,

Ok, it might be the time to post these experimental IPv6 patches for IPVS
again to get some comments and help. Since the last time, I've worked on
reducing a lot of unnecessary code duplication, but some is still there
where it was harder to get rid of. Also, we've implemented a genetlink
interface (the first two patches in this series are exactly the v4
version of that) and updated ipvsadm to work with it, so we do not have
to break the existing sockopt userspace interface. Of course, there are
also many other small fixes and changes since the last version.

- Full kernel patch in one file against davem's net-2.6:
http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6.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] 59+ messages in thread

* [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 02/24] IPVS: Add genetlink interface implementation Julius Volz
                   ` (23 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add IPVS Generic Netlink interface definitions to include/linux/ip_vs.h.

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

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

diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index ec6eb49..0f434a2 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -242,4 +242,164 @@ struct ip_vs_daemon_user {
 	int			syncid;
 };
 
+/*
+ *
+ * IPVS Generic Netlink interface definitions
+ *
+ */
+
+/* Generic Netlink family info */
+
+#define IPVS_GENL_NAME		"IPVS"
+#define IPVS_GENL_VERSION	0x1
+
+struct ip_vs_flags {
+	__be32 flags;
+	__be32 mask;
+};
+
+/* Generic Netlink command attributes */
+enum {
+	IPVS_CMD_UNSPEC = 0,
+
+	IPVS_CMD_NEW_SERVICE,		/* add service */
+	IPVS_CMD_SET_SERVICE,		/* modify service */
+	IPVS_CMD_DEL_SERVICE,		/* delete service */
+	IPVS_CMD_GET_SERVICE,		/* get service info */
+
+	IPVS_CMD_NEW_DEST,		/* add destination */
+	IPVS_CMD_SET_DEST,		/* modify destination */
+	IPVS_CMD_DEL_DEST,		/* delete destination */
+	IPVS_CMD_GET_DEST,		/* get destination info */
+
+	IPVS_CMD_NEW_DAEMON,		/* start sync daemon */
+	IPVS_CMD_DEL_DAEMON,		/* stop sync daemon */
+	IPVS_CMD_GET_DAEMON,		/* get sync daemon status */
+
+	IPVS_CMD_SET_CONFIG,		/* set config settings */
+	IPVS_CMD_GET_CONFIG,		/* get config settings */
+
+	IPVS_CMD_SET_INFO,		/* only used in GET_INFO reply */
+	IPVS_CMD_GET_INFO,		/* get general IPVS info */
+
+	IPVS_CMD_ZERO,			/* zero all counters and stats */
+	IPVS_CMD_FLUSH,			/* flush services and dests */
+
+	__IPVS_CMD_MAX,
+};
+
+#define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1)
+
+/* Attributes used in the first level of commands */
+enum {
+	IPVS_CMD_ATTR_UNSPEC = 0,
+	IPVS_CMD_ATTR_SERVICE,		/* nested service attribute */
+	IPVS_CMD_ATTR_DEST,		/* nested destination attribute */
+	IPVS_CMD_ATTR_DAEMON,		/* nested sync daemon attribute */
+	IPVS_CMD_ATTR_TIMEOUT_TCP,	/* TCP connection timeout */
+	IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,	/* TCP FIN wait timeout */
+	IPVS_CMD_ATTR_TIMEOUT_UDP,	/* UDP timeout */
+	__IPVS_CMD_ATTR_MAX,
+};
+
+#define IPVS_CMD_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe a service
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_SERVICE
+ */
+enum {
+	IPVS_SVC_ATTR_UNSPEC = 0,
+	IPVS_SVC_ATTR_AF,		/* address family */
+	IPVS_SVC_ATTR_PROTOCOL,		/* virtual service protocol */
+	IPVS_SVC_ATTR_ADDR,		/* virtual service address */
+	IPVS_SVC_ATTR_PORT,		/* virtual service port */
+	IPVS_SVC_ATTR_FWMARK,		/* firewall mark of service */
+
+	IPVS_SVC_ATTR_SCHED_NAME,	/* name of scheduler */
+	IPVS_SVC_ATTR_FLAGS,		/* virtual service flags */
+	IPVS_SVC_ATTR_TIMEOUT,		/* persistent timeout */
+	IPVS_SVC_ATTR_NETMASK,		/* persistent netmask */
+
+	IPVS_SVC_ATTR_STATS,		/* nested attribute for service stats */
+	__IPVS_SVC_ATTR_MAX,
+};
+
+#define IPVS_SVC_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe a destination (real server)
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_DEST
+ */
+enum {
+	IPVS_DEST_ATTR_UNSPEC = 0,
+	IPVS_DEST_ATTR_ADDR,		/* real server address */
+	IPVS_DEST_ATTR_PORT,		/* real server port */
+
+	IPVS_DEST_ATTR_FWD_METHOD,	/* forwarding method */
+	IPVS_DEST_ATTR_WEIGHT,		/* destination weight */
+
+	IPVS_DEST_ATTR_U_THRESH,	/* upper threshold */
+	IPVS_DEST_ATTR_L_THRESH,	/* lower threshold */
+
+	IPVS_DEST_ATTR_ACTIVE_CONNS,	/* active connections */
+	IPVS_DEST_ATTR_INACT_CONNS,	/* inactive connections */
+	IPVS_DEST_ATTR_PERSIST_CONNS,	/* persistent connections */
+
+	IPVS_DEST_ATTR_STATS,		/* nested attribute for dest stats */
+	__IPVS_DEST_ATTR_MAX,
+};
+
+#define IPVS_DEST_ATTR_MAX (__IPVS_DEST_ATTR_MAX - 1)
+
+/*
+ * Attributes describing a sync daemon
+ *
+ * Used inside nested attribute IPVS_CMD_ATTR_DAEMON
+ */
+enum {
+	IPVS_DAEMON_ATTR_UNSPEC = 0,
+	IPVS_DAEMON_ATTR_STATE,		/* sync daemon state (master/backup) */
+	IPVS_DAEMON_ATTR_MCAST_IFN,	/* multicast interface name */
+	IPVS_DAEMON_ATTR_SYNC_ID,	/* SyncID we belong to */
+	__IPVS_DAEMON_ATTR_MAX,
+};
+
+#define IPVS_DAEMON_ATTR_MAX (__IPVS_DAEMON_ATTR_MAX - 1)
+
+/*
+ * Attributes used to describe service or destination entry statistics
+ *
+ * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS
+ */
+enum {
+	IPVS_STATS_ATTR_UNSPEC = 0,
+	IPVS_STATS_ATTR_CONNS,		/* connections scheduled */
+	IPVS_STATS_ATTR_INPKTS,		/* incoming packets */
+	IPVS_STATS_ATTR_OUTPKTS,	/* outgoing packets */
+	IPVS_STATS_ATTR_INBYTES,	/* incoming bytes */
+	IPVS_STATS_ATTR_OUTBYTES,	/* outgoing bytes */
+
+	IPVS_STATS_ATTR_CPS,		/* current connection rate */
+	IPVS_STATS_ATTR_INPPS,		/* current in packet rate */
+	IPVS_STATS_ATTR_OUTPPS,		/* current out packet rate */
+	IPVS_STATS_ATTR_INBPS,		/* current in byte rate */
+	IPVS_STATS_ATTR_OUTBPS,		/* current out byte rate */
+	__IPVS_STATS_ATTR_MAX,
+};
+
+#define IPVS_STATS_ATTR_MAX (__IPVS_STATS_ATTR_MAX - 1)
+
+/* Attributes used in response to IPVS_CMD_GET_INFO command */
+enum {
+	IPVS_INFO_ATTR_UNSPEC = 0,
+	IPVS_INFO_ATTR_VERSION,		/* IPVS version number */
+	IPVS_INFO_ATTR_CONN_TAB_SIZE,	/* size of connection hash table */
+	__IPVS_INFO_ATTR_MAX,
+};
+
+#define IPVS_INFO_ATTR_MAX (__IPVS_INFO_ATTR_MAX - 1)
+
 #endif	/* _IP_VS_H */
-- 
1.5.4.5


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

* [PATCH RFC 02/24] IPVS: Add genetlink interface implementation
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 03/24] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
                   ` (22 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add the implementation of the new Generic Netlink interface to IPVS and
keep the old set/getsockopt interface for userspace backwards
compatibility.

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

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

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6379705..d1dbd8b 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -37,6 +37,7 @@
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/sock.h>
+#include <net/genetlink.h>
 
 #include <asm/uaccess.h>
 
@@ -2320,6 +2321,872 @@ static struct nf_sockopt_ops ip_vs_sockopts = {
 	.owner		= THIS_MODULE,
 };
 
+/*
+ * Generic Netlink interface
+ */
+
+/* IPVS genetlink family */
+static struct genl_family ip_vs_genl_family = {
+	.id		= GENL_ID_GENERATE,
+	.hdrsize	= 0,
+	.name		= IPVS_GENL_NAME,
+	.version	= IPVS_GENL_VERSION,
+	.maxattr	= IPVS_CMD_MAX,
+};
+
+/* Policy used for first-level command attributes */
+static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = {
+	[IPVS_CMD_ATTR_SERVICE]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_DEST]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_DAEMON]		= { .type = NLA_NESTED },
+	[IPVS_CMD_ATTR_TIMEOUT_TCP]	= { .type = NLA_U32 },
+	[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]	= { .type = NLA_U32 },
+	[IPVS_CMD_ATTR_TIMEOUT_UDP]	= { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */
+static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
+	[IPVS_DAEMON_ATTR_STATE]	= { .type = NLA_U32 },
+	[IPVS_DAEMON_ATTR_MCAST_IFN]	= { .type = NLA_NUL_STRING,
+					    .len = IP_VS_IFNAME_MAXLEN },
+	[IPVS_DAEMON_ATTR_SYNC_ID]	= { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
+static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
+	[IPVS_SVC_ATTR_AF]		= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_PROTOCOL]	= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_ADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(union nf_inet_addr) },
+	[IPVS_SVC_ATTR_PORT]		= { .type = NLA_U16 },
+	[IPVS_SVC_ATTR_FWMARK]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_SCHED_NAME]	= { .type = NLA_NUL_STRING,
+					    .len = IP_VS_SCHEDNAME_MAXLEN },
+	[IPVS_SVC_ATTR_FLAGS]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct ip_vs_flags) },
+	[IPVS_SVC_ATTR_TIMEOUT]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_NETMASK]		= { .type = NLA_U32 },
+	[IPVS_SVC_ATTR_STATS]		= { .type = NLA_NESTED },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DEST */
+static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
+	[IPVS_DEST_ATTR_ADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(union nf_inet_addr) },
+	[IPVS_DEST_ATTR_PORT]		= { .type = NLA_U16 },
+	[IPVS_DEST_ATTR_FWD_METHOD]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_WEIGHT]		= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_U_THRESH]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_L_THRESH]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_ACTIVE_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_INACT_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_PERSIST_CONNS]	= { .type = NLA_U32 },
+	[IPVS_DEST_ATTR_STATS]		= { .type = NLA_NESTED },
+};
+
+static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
+				 struct ip_vs_stats *stats)
+{
+	struct nlattr *nl_stats = nla_nest_start(skb, container_type);
+	if (!nl_stats)
+		return -EMSGSIZE;
+
+	spin_lock_bh(&stats->lock);
+
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->conns);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->inpkts);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->outpkts);
+	NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->inbytes);
+	NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->outbytes);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->cps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->inpps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->outpps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->inbps);
+	NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->outbps);
+
+	spin_unlock_bh(&stats->lock);
+
+	nla_nest_end(skb, nl_stats);
+
+	return 0;
+
+nla_put_failure:
+	spin_unlock_bh(&stats->lock);
+	nla_nest_cancel(skb, nl_stats);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_fill_service(struct sk_buff *skb,
+				   struct ip_vs_service *svc)
+{
+	struct nlattr *nl_service;
+	struct ip_vs_flags flags = { .flags = svc->flags,
+				     .mask = ~0 };
+
+	nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
+	if (!nl_service)
+		return -EMSGSIZE;
+
+	NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET);
+
+	if (svc->fwmark) {
+		NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
+	} else {
+		NLA_PUT_U16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol);
+		NLA_PUT(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr);
+		NLA_PUT_U16(skb, IPVS_SVC_ATTR_PORT, svc->port);
+	}
+
+	NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
+	NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
+	NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
+	NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
+
+	if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nl_service);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_service);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_service(struct sk_buff *skb,
+				   struct ip_vs_service *svc,
+				   struct netlink_callback *cb)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_SERVICE);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_service(skb, svc) < 0)
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_services(struct sk_buff *skb,
+				    struct netlink_callback *cb)
+{
+	int idx = 0, i;
+	int start = cb->args[0];
+	struct ip_vs_service *svc;
+
+	mutex_lock(&__ip_vs_mutex);
+	for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
+		list_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {
+			if (++idx <= start)
+				continue;
+			if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
+				idx--;
+				goto nla_put_failure;
+			}
+		}
+	}
+
+	for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
+		list_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {
+			if (++idx <= start)
+				continue;
+			if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
+				idx--;
+				goto nla_put_failure;
+			}
+		}
+	}
+
+nla_put_failure:
+	mutex_unlock(&__ip_vs_mutex);
+	cb->args[0] = idx;
+
+	return skb->len;
+}
+
+static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
+				    struct nlattr *nla, int full_entry)
+{
+	struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
+	struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr;
+
+	/* Parse mandatory identifying service fields first */
+	if (nla == NULL ||
+	    nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla, ip_vs_svc_policy))
+		return -EINVAL;
+
+	nla_af		= attrs[IPVS_SVC_ATTR_AF];
+	nla_protocol	= attrs[IPVS_SVC_ATTR_PROTOCOL];
+	nla_addr	= attrs[IPVS_SVC_ATTR_ADDR];
+	nla_port	= attrs[IPVS_SVC_ATTR_PORT];
+	nla_fwmark	= attrs[IPVS_SVC_ATTR_FWMARK];
+
+	if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
+		return -EINVAL;
+
+	/* For now, only support IPv4 */
+	if (nla_get_u16(nla_af) != AF_INET)
+		return -EAFNOSUPPORT;
+
+	if (nla_fwmark) {
+		usvc->protocol = IPPROTO_TCP;
+		usvc->fwmark = nla_get_u32(nla_fwmark);
+	} else {
+		usvc->protocol = nla_get_u16(nla_protocol);
+		nla_memcpy(&usvc->addr, nla_addr, sizeof(usvc->addr));
+		usvc->port = nla_get_u16(nla_port);
+		usvc->fwmark = 0;
+	}
+
+	/* If a full entry was requested, check for the additional fields */
+	if (full_entry) {
+		struct nlattr *nla_sched, *nla_flags, *nla_timeout,
+			      *nla_netmask;
+		struct ip_vs_flags flags;
+		struct ip_vs_service *svc;
+
+		nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
+		nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
+		nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
+		nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
+
+		if (!(nla_sched && nla_flags && nla_timeout && nla_netmask))
+			return -EINVAL;
+
+		nla_memcpy(&flags, nla_flags, sizeof(flags));
+
+		/* prefill flags from service if it already exists */
+		if (usvc->fwmark)
+			svc = __ip_vs_svc_fwm_get(usvc->fwmark);
+		else
+			svc = __ip_vs_service_get(usvc->protocol, usvc->addr,
+						  usvc->port);
+		if (svc) {
+			usvc->flags = svc->flags;
+			ip_vs_service_put(svc);
+		} else
+			usvc->flags = 0;
+
+		/* 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->timeout = nla_get_u32(nla_timeout);
+		usvc->netmask = nla_get_u32(nla_netmask);
+	}
+
+	return 0;
+}
+
+static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
+{
+	struct ip_vs_service_user usvc;
+	int ret;
+
+	ret = ip_vs_genl_parse_service(&usvc, nla, 0);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (usvc.fwmark)
+		return __ip_vs_svc_fwm_get(usvc.fwmark);
+	else
+		return __ip_vs_service_get(usvc.protocol, usvc.addr,
+					   usvc.port);
+}
+
+static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
+{
+	struct nlattr *nl_dest;
+
+	nl_dest = nla_nest_start(skb, IPVS_CMD_ATTR_DEST);
+	if (!nl_dest)
+		return -EMSGSIZE;
+
+	NLA_PUT(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr);
+	NLA_PUT_U16(skb, IPVS_DEST_ATTR_PORT, dest->port);
+
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_FWD_METHOD,
+		    atomic_read(&dest->conn_flags) & IP_VS_CONN_F_FWD_MASK);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_WEIGHT, atomic_read(&dest->weight));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold);
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
+		    atomic_read(&dest->activeconns));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_INACT_CONNS,
+		    atomic_read(&dest->inactconns));
+	NLA_PUT_U32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
+		    atomic_read(&dest->persistconns));
+
+	if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats))
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nl_dest);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_dest);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_dest(struct sk_buff *skb, struct ip_vs_dest *dest,
+				struct netlink_callback *cb)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_DEST);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_dest(skb, dest) < 0)
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_dests(struct sk_buff *skb,
+				 struct netlink_callback *cb)
+{
+	int idx = 0;
+	int start = cb->args[0];
+	struct ip_vs_service *svc;
+	struct ip_vs_dest *dest;
+	struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1];
+
+	mutex_lock(&__ip_vs_mutex);
+
+	/* Try to find the service for which to dump destinations */
+	if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs,
+			IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy))
+		goto out_err;
+
+	svc = ip_vs_genl_find_service(attrs[IPVS_CMD_ATTR_SERVICE]);
+	if (IS_ERR(svc) || svc == NULL)
+		goto out_err;
+
+	/* Dump the destinations */
+	list_for_each_entry(dest, &svc->destinations, n_list) {
+		if (++idx <= start)
+			continue;
+		if (ip_vs_genl_dump_dest(skb, dest, cb) < 0) {
+			idx--;
+			goto nla_put_failure;
+		}
+	}
+
+nla_put_failure:
+	cb->args[0] = idx;
+	ip_vs_service_put(svc);
+
+out_err:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return skb->len;
+}
+
+static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
+				 struct nlattr *nla, int full_entry)
+{
+	struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
+	struct nlattr *nla_addr, *nla_port;
+
+	/* Parse mandatory identifying destination fields first */
+	if (nla == NULL ||
+	    nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla, ip_vs_dest_policy))
+		return -EINVAL;
+
+	nla_addr	= attrs[IPVS_DEST_ATTR_ADDR];
+	nla_port	= attrs[IPVS_DEST_ATTR_PORT];
+
+	if (!(nla_addr && nla_port))
+		return -EINVAL;
+
+	nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr));
+	udest->port = nla_get_u16(nla_port);
+
+	/* If a full entry was requested, check for the additional fields */
+	if (full_entry) {
+		struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh,
+			      *nla_l_thresh;
+
+		nla_fwd		= attrs[IPVS_DEST_ATTR_FWD_METHOD];
+		nla_weight	= attrs[IPVS_DEST_ATTR_WEIGHT];
+		nla_u_thresh	= attrs[IPVS_DEST_ATTR_U_THRESH];
+		nla_l_thresh	= attrs[IPVS_DEST_ATTR_L_THRESH];
+
+		if (!(nla_fwd && nla_weight && nla_u_thresh && nla_l_thresh))
+			return -EINVAL;
+
+		udest->conn_flags = nla_get_u32(nla_fwd)
+				    & IP_VS_CONN_F_FWD_MASK;
+		udest->weight = nla_get_u32(nla_weight);
+		udest->u_threshold = nla_get_u32(nla_u_thresh);
+		udest->l_threshold = nla_get_u32(nla_l_thresh);
+	}
+
+	return 0;
+}
+
+static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state,
+				  const char *mcast_ifn, __be32 syncid)
+{
+	struct nlattr *nl_daemon;
+
+	nl_daemon = nla_nest_start(skb, IPVS_CMD_ATTR_DAEMON);
+	if (!nl_daemon)
+		return -EMSGSIZE;
+
+	NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_STATE, state);
+	NLA_PUT_STRING(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn);
+	NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid);
+
+	nla_nest_end(skb, nl_daemon);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nl_daemon);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __be32 state,
+				  const char *mcast_ifn, __be32 syncid,
+				  struct netlink_callback *cb)
+{
+	void *hdr;
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			  &ip_vs_genl_family, NLM_F_MULTI,
+			  IPVS_CMD_NEW_DAEMON);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (ip_vs_genl_fill_daemon(skb, state, mcast_ifn, syncid))
+		goto nla_put_failure;
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
+				   struct netlink_callback *cb)
+{
+	mutex_lock(&__ip_vs_mutex);
+	if ((ip_vs_sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
+		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
+					   ip_vs_master_mcast_ifn,
+					   ip_vs_master_syncid, cb) < 0)
+			goto nla_put_failure;
+
+		cb->args[0] = 1;
+	}
+
+	if ((ip_vs_sync_state & IP_VS_STATE_BACKUP) && !cb->args[1]) {
+		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_BACKUP,
+					   ip_vs_backup_mcast_ifn,
+					   ip_vs_backup_syncid, cb) < 0)
+			goto nla_put_failure;
+
+		cb->args[1] = 1;
+	}
+
+nla_put_failure:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return skb->len;
+}
+
+static int ip_vs_genl_new_daemon(struct nlattr **attrs)
+{
+	if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
+	      attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
+	      attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
+		return -EINVAL;
+
+	return start_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
+				 nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
+				 nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
+}
+
+static int ip_vs_genl_del_daemon(struct nlattr **attrs)
+{
+	if (!attrs[IPVS_DAEMON_ATTR_STATE])
+		return -EINVAL;
+
+	return stop_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
+}
+
+static int ip_vs_genl_set_config(struct nlattr **attrs)
+{
+	struct ip_vs_timeout_user t;
+
+	__ip_vs_get_timeouts(&t);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP])
+		t.tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN])
+		t.tcp_fin_timeout =
+			nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]);
+
+	if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP])
+		t.udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]);
+
+	return ip_vs_set_timeout(&t);
+}
+
+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;
+	int ret = 0, cmd;
+	int need_full_svc = 0, need_full_dest = 0;
+
+	cmd = info->genlhdr->cmd;
+
+	mutex_lock(&__ip_vs_mutex);
+
+	if (cmd == IPVS_CMD_FLUSH) {
+		ret = ip_vs_flush();
+		goto out;
+	} else if (cmd == IPVS_CMD_SET_CONFIG) {
+		ret = ip_vs_genl_set_config(info->attrs);
+		goto out;
+	} else if (cmd == IPVS_CMD_NEW_DAEMON ||
+		   cmd == IPVS_CMD_DEL_DAEMON) {
+
+		struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
+
+		if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
+		    nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
+				     info->attrs[IPVS_CMD_ATTR_DAEMON],
+				     ip_vs_daemon_policy)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (cmd == IPVS_CMD_NEW_DAEMON)
+			ret = ip_vs_genl_new_daemon(daemon_attrs);
+		else
+			ret = ip_vs_genl_del_daemon(daemon_attrs);
+		goto out;
+	} else if (cmd == IPVS_CMD_ZERO &&
+		   !info->attrs[IPVS_CMD_ATTR_SERVICE]) {
+		ret = ip_vs_zero_all();
+		goto out;
+	}
+
+	/* All following commands require a service argument, so check if we
+	 * received a valid one. We need a full service specification when
+	 * adding / editing a service. Only identifying members otherwise. */
+	if (cmd == IPVS_CMD_NEW_SERVICE || cmd == IPVS_CMD_SET_SERVICE)
+		need_full_svc = 1;
+
+	ret = ip_vs_genl_parse_service(&usvc,
+				       info->attrs[IPVS_CMD_ATTR_SERVICE],
+				       need_full_svc);
+	if (ret)
+		goto out;
+
+	/* 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);
+	else
+		svc = __ip_vs_svc_fwm_get(usvc.fwmark);
+
+	/* Unless we're adding a new service, the service must already exist */
+	if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
+		ret = -ESRCH;
+		goto out;
+	}
+
+	/* Destination commands require a valid destination argument. For
+	 * adding / editing a destination, we need a full destination
+	 * specification. */
+	if (cmd == IPVS_CMD_NEW_DEST || cmd == IPVS_CMD_SET_DEST ||
+	    cmd == IPVS_CMD_DEL_DEST) {
+		if (cmd != IPVS_CMD_DEL_DEST)
+			need_full_dest = 1;
+
+		ret = ip_vs_genl_parse_dest(&udest,
+					    info->attrs[IPVS_CMD_ATTR_DEST],
+					    need_full_dest);
+		if (ret)
+			goto out;
+	}
+
+	switch (cmd) {
+	case IPVS_CMD_NEW_SERVICE:
+		if (svc == NULL)
+			ret = ip_vs_add_service(&usvc, &svc);
+		else
+			ret = -EEXIST;
+		break;
+	case IPVS_CMD_SET_SERVICE:
+		ret = ip_vs_edit_service(svc, &usvc);
+		break;
+	case IPVS_CMD_DEL_SERVICE:
+		ret = ip_vs_del_service(svc);
+		break;
+	case IPVS_CMD_NEW_DEST:
+		ret = ip_vs_add_dest(svc, &udest);
+		break;
+	case IPVS_CMD_SET_DEST:
+		ret = ip_vs_edit_dest(svc, &udest);
+		break;
+	case IPVS_CMD_DEL_DEST:
+		ret = ip_vs_del_dest(svc, &udest);
+		break;
+	case IPVS_CMD_ZERO:
+		ret = ip_vs_zero_service(svc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+out:
+	if (svc)
+		ip_vs_service_put(svc);
+	mutex_unlock(&__ip_vs_mutex);
+
+	return ret;
+}
+
+static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *msg;
+	void *reply;
+	int ret, cmd, reply_cmd;
+
+	cmd = info->genlhdr->cmd;
+
+	if (cmd == IPVS_CMD_GET_SERVICE)
+		reply_cmd = IPVS_CMD_NEW_SERVICE;
+	else if (cmd == IPVS_CMD_GET_INFO)
+		reply_cmd = IPVS_CMD_SET_INFO;
+	else if (cmd == IPVS_CMD_GET_CONFIG)
+		reply_cmd = IPVS_CMD_SET_CONFIG;
+	else {
+		IP_VS_ERR("unknown Generic Netlink command\n");
+		return -EINVAL;
+	}
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	mutex_lock(&__ip_vs_mutex);
+
+	reply = genlmsg_put_reply(msg, info, &ip_vs_genl_family, 0, reply_cmd);
+	if (reply == NULL)
+		goto nla_put_failure;
+
+	switch (cmd) {
+	case IPVS_CMD_GET_SERVICE:
+	{
+		struct ip_vs_service *svc;
+
+		svc = ip_vs_genl_find_service(info->attrs[IPVS_CMD_ATTR_SERVICE]);
+		if (IS_ERR(svc)) {
+			ret = PTR_ERR(svc);
+			goto out_err;
+		} else if (svc) {
+			ret = ip_vs_genl_fill_service(msg, svc);
+			ip_vs_service_put(svc);
+			if (ret)
+				goto nla_put_failure;
+		} else {
+			ret = -ESRCH;
+			goto out_err;
+		}
+
+		break;
+	}
+
+	case IPVS_CMD_GET_CONFIG:
+	{
+		struct ip_vs_timeout_user t;
+
+		__ip_vs_get_timeouts(&t);
+#ifdef CONFIG_IP_VS_PROTO_TCP
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, t.tcp_timeout);
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,
+			    t.tcp_fin_timeout);
+#endif
+#ifdef CONFIG_IP_VS_PROTO_UDP
+		NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout);
+#endif
+
+		break;
+	}
+
+	case IPVS_CMD_GET_INFO:
+		NLA_PUT_U32(msg, IPVS_INFO_ATTR_VERSION, IP_VS_VERSION_CODE);
+		NLA_PUT_U32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE,
+			    IP_VS_CONN_TAB_SIZE);
+		break;
+	}
+
+	genlmsg_end(msg, reply);
+	ret = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+nla_put_failure:
+	IP_VS_ERR("not enough space in Netlink message\n");
+	ret = -EMSGSIZE;
+
+out_err:
+	nlmsg_free(msg);
+out:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return ret;
+}
+
+
+static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+	{
+		.cmd	= IPVS_CMD_NEW_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_SERVICE,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+		.dumpit	= ip_vs_genl_dump_services,
+		.policy	= ip_vs_cmd_policy,
+	},
+	{
+		.cmd	= IPVS_CMD_NEW_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_DEST,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.dumpit	= ip_vs_genl_dump_dests,
+	},
+	{
+		.cmd	= IPVS_CMD_NEW_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_DEL_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_DAEMON,
+		.flags	= GENL_ADMIN_PERM,
+		.dumpit	= ip_vs_genl_dump_daemons,
+	},
+	{
+		.cmd	= IPVS_CMD_SET_CONFIG,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_CONFIG,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_GET_INFO,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_get_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_ZERO,
+		.flags	= GENL_ADMIN_PERM,
+		.policy	= ip_vs_cmd_policy,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+	{
+		.cmd	= IPVS_CMD_FLUSH,
+		.flags	= GENL_ADMIN_PERM,
+		.doit	= ip_vs_genl_set_cmd,
+	},
+};
+
+static int __init ip_vs_genl_register(void)
+{
+	int ret, i;
+
+	ret = genl_register_family(&ip_vs_genl_family);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) {
+		ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]);
+		if (ret)
+			goto err_out;
+	}
+	return 0;
+
+err_out:
+	genl_unregister_family(&ip_vs_genl_family);
+	return ret;
+}
+
+static void ip_vs_genl_unregister(void)
+{
+	genl_unregister_family(&ip_vs_genl_family);
+}
+
+/* End of Generic Netlink interface definitions */
+
 
 int __init ip_vs_control_init(void)
 {
@@ -2334,6 +3201,13 @@ int __init ip_vs_control_init(void)
 		return ret;
 	}
 
+	ret = ip_vs_genl_register();
+	if (ret) {
+		IP_VS_ERR("cannot register Generic Netlink interface.\n");
+		nf_unregister_sockopt(&ip_vs_sockopts);
+		return ret;
+	}
+
 	proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops);
 	proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops);
 
@@ -2368,6 +3242,7 @@ void ip_vs_control_cleanup(void)
 	unregister_sysctl_table(sysctl_header);
 	proc_net_remove(&init_net, "ip_vs_stats");
 	proc_net_remove(&init_net, "ip_vs");
+	ip_vs_genl_unregister();
 	nf_unregister_sockopt(&ip_vs_sockopts);
 	LeaveFunction(2);
 }
-- 
1.5.4.5


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

* [PATCH RFC 03/24] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 02/24] IPVS: Add genetlink interface implementation Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
                   ` (21 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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 09d0c3f..fd24182 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] 59+ messages in thread

* [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (2 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 03/24] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
                   ` (20 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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. Add extended internal versions of 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).

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

 1 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7312c3d..e41a164 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;
@@ -305,6 +309,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
  */
@@ -314,8 +357,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 +386,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 +411,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 */
 };
-- 
1.5.4.5


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

* [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (3 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output Julius Volz
                   ` (19 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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, 50 insertions(+), 0 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index e41a164..016af19 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -25,6 +25,56 @@
 #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
+	return (af == AF_INET) ? (a->ip == b->ip)
+			       : ipv6_addr_equal(&a->in6, &b->in6);
+#else
+	return a->ip == b->ip;
+#endif
+}
+
 #ifdef CONFIG_IP_VS_DEBUG
 #include <linux/net.h>
 
-- 
1.5.4.5


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

* [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (4 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 07/24] IPVS: Convert existing debug uses to use new macros Julius Volz
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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, 43 insertions(+), 0 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 016af19..82037b7 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -79,6 +79,47 @@ 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_INET)
+#endif
+		len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
+			       NIPQUAD(addr->ip)) + 1;
+#ifdef CONFIG_IP_VS_IPV6
+	else
+		len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
+			       NIP6(addr->in6)) + 1;
+#endif
+
+	*idx += len;
+	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() macro */
+#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())	\
@@ -101,6 +142,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] 59+ messages in thread

* [PATCH RFC 07/24] IPVS: Convert existing debug uses to use new macros
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (5 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6 Julius Volz
                   ` (17 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Convert existing debugging outputs to use the newly introduced debugging
macros where appropriate.

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

 13 files changed, 213 insertions(+), 180 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 82037b7..fbf57c2 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -670,24 +670,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);
@@ -697,23 +705,27 @@ 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);
 }
 
-
 /*
  *      IPVS application functions
  *      (from ip_vs_app.c)
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 44a6872..ea921dc 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -222,11 +222,11 @@ struct ip_vs_conn *ip_vs_conn_in_get
 	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
 		cp = __ip_vs_conn_in_get(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;
 }
@@ -257,11 +257,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;
 }
@@ -298,11 +298,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;
 }
@@ -402,16 +402,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), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), 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)) {
@@ -464,16 +464,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), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), 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)) {
@@ -526,13 +526,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), ntohs(ct->cport),
-			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
-			  NIPQUAD(ct->daddr), 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_core.c b/net/ipv4/ipvs/ip_vs_core.c
index a7879ea..63c08c4 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -182,11 +182,11 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
 	/* Mask saddr with the netmask to adjust template granularity */
 	snet = iph->saddr & 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(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
@@ -386,13 +386,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), ntohs(cp->cport),
-		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
-		  NIPQUAD(cp->daddr), 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;
@@ -909,10 +909,10 @@ 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",
+		IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
 			  skb->pkt_type,
-			  ip_hdr(skb)->protocol,
-			  NIPQUAD(ip_hdr(skb)->daddr));
+			  iph.protocol,
+			  IP_VS_DBG_ADDR(af, &iph.daddr));
 		return NF_ACCEPT;
 	}
 
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index d1dbd8b..efa34fb 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -449,10 +449,10 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
   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;
 }
@@ -623,11 +623,12 @@ 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), ntohs(dest->port),
-			  atomic_read(&dest->refcnt));
+		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->addr == daddr &&
 		    dest->port == dport &&
 		    dest->vfwmark == svc->fwmark &&
@@ -643,10 +644,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), 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);
@@ -841,14 +843,16 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 	 * is from the same service
 	 */
 	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),
-			  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);
 
 		/*
@@ -988,10 +992,12 @@ 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), 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_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index ebcdbf7..b8670ec 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -84,11 +84,13 @@ 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),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->inactconns));
+	if (!least)
+		return NULL;
+
+	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;
 }
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index 92f3a67..af277bc 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -120,12 +120,13 @@ 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), 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;
 }
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index 73e0ea8..ee40aef 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -66,12 +66,12 @@ ah_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;
@@ -99,12 +99,12 @@ ah_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 	}
 
 	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;
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
index 21d70c8..51950e3 100644
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_esp.c
@@ -66,12 +66,12 @@ 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;
@@ -99,12 +99,12 @@ esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 	}
 
 	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;
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index d0ea467..4689d94 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -419,19 +419,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), ntohs(cp->dport),
-			  NIPQUAD(cp->caddr), 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)) {
@@ -546,12 +549,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), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), 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 c6be5d5..e06020b 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -340,12 +340,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), ntohs(cp->cport),
-				  NIPQUAD(cp->vaddr), 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_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 77663d8..33d93b0 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -122,12 +122,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), 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;
 }
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index 9b0ef86..76e3339 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -110,12 +110,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), 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;
 }
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 0d86a79..2f618dc 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), 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);
-- 
1.5.4.5


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

* [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (6 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 07/24] IPVS: Convert existing debug uses to use new macros Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-21 13:29   ` Brian Haley
  2008-08-20 16:15 ` [PATCH RFC 09/24] IPVS: Add IPv6 Netfilter hooks and add/modify support functions Julius Volz
                   ` (16 subsequent siblings)
  24 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add 'af' argument to protocol handler functions and make them handle both
IPv4 and IPv6 in the same function. Change the protocol debugging functions
to detect the AF from the skb and generate the appropriate output. Probably
still too much duplication here.

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

 6 files changed, 430 insertions(+), 160 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fbf57c2..9ba9ee7 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -298,21 +298,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);
 
@@ -322,7 +324,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);
 
@@ -909,6 +912,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.c b/net/ipv4/ipvs/ip_vs_proto.c
index 6099a88..301b779 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;
@@ -168,8 +168,8 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
 			pp->name, NIPQUAD(ih->saddr),
 			NIPQUAD(ih->daddr));
 	else {
-		__be16 _ports[2], *pptr
-;
+		__be16 _ports[2], *pptr;
+
 		pptr = skb_header_pointer(skb, offset + ih->ihl*4,
 					  sizeof(_ports), _ports);
 		if (pptr == NULL)
@@ -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.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index ee40aef..843936c 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -39,25 +39,23 @@ struct isakmp_hdr {
 
 
 static struct ip_vs_conn *
-ah_conn_in_get(const struct sk_buff *skb,
-	       struct ip_vs_protocol *pp,
-	       const struct iphdr *iph,
-	       unsigned int proto_off,
+ah_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,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP),
-				       iph->daddr,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP),
-				       iph->saddr,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP));
 	}
 
@@ -79,22 +77,23 @@ ah_conn_in_get(const struct sk_buff *skb,
 
 
 static struct ip_vs_conn *
-ah_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct iphdr *iph, unsigned int proto_off, int inverse)
+ah_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,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->saddr,
 					htons(PORT_ISAKMP),
-					iph->daddr,
+					&iph->daddr,
 					htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->daddr,
 					htons(PORT_ISAKMP),
-					iph->saddr,
+					&iph->saddr,
 					htons(PORT_ISAKMP));
 	}
 
@@ -112,8 +111,7 @@ ah_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-ah_conn_schedule(struct sk_buff *skb,
-		 struct ip_vs_protocol *pp,
+ah_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		 int *verdict, struct ip_vs_conn **cpp)
 {
 	/*
@@ -125,8 +123,8 @@ ah_conn_schedule(struct sk_buff *skb,
 
 
 static void
-ah_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
-		int offset, const char *msg)
+ah_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 +140,38 @@ ah_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_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_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_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		ah_debug_packet_v4(pp, skb, offset, msg);
+}
+
 
 static void ah_init(struct ip_vs_protocol *pp)
 {
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
index 51950e3..9c36930 100644
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_esp.c
@@ -39,25 +39,23 @@ struct isakmp_hdr {
 
 
 static struct ip_vs_conn *
-esp_conn_in_get(const struct sk_buff *skb,
-		struct ip_vs_protocol *pp,
-		const struct iphdr *iph,
-		unsigned int proto_off,
+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,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP),
-				       iph->daddr,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_in_get(IPPROTO_UDP,
-				       iph->daddr,
+		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
+				       &iph->daddr,
 				       htons(PORT_ISAKMP),
-				       iph->saddr,
+				       &iph->saddr,
 				       htons(PORT_ISAKMP));
 	}
 
@@ -79,22 +77,23 @@ esp_conn_in_get(const struct sk_buff *skb,
 
 
 static struct ip_vs_conn *
-esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct iphdr *iph, unsigned int proto_off, int inverse)
+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,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->saddr,
 					htons(PORT_ISAKMP),
-					iph->daddr,
+					&iph->daddr,
 					htons(PORT_ISAKMP));
 	} else {
-		cp = ip_vs_conn_out_get(IPPROTO_UDP,
-					iph->daddr,
+		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
+					&iph->daddr,
 					htons(PORT_ISAKMP),
-					iph->saddr,
+					&iph->saddr,
 					htons(PORT_ISAKMP));
 	}
 
@@ -112,7 +111,7 @@ esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-esp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
+esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		  int *verdict, struct ip_vs_conn **cpp)
 {
 	/*
@@ -124,8 +123,8 @@ esp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static void
-esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
-		 int offset, const char *msg)
+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;
@@ -141,6 +140,37 @@ 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
+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
+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))
+		esp_debug_packet_v6(pp, skb, offset, msg);
+	else
+#endif
+		esp_debug_packet_v4(pp, skb, offset, msg);
+}
 
 static void esp_init(struct ip_vs_protocol *pp)
 {
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 4689d94..c59b737 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
  *
  */
 
@@ -25,8 +26,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;
 
@@ -35,19 +37,20 @@ tcp_conn_in_get(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, pptr[0],
-					 iph->daddr, 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, pptr[1],
-					 iph->saddr, pptr[0]);
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->daddr, pptr[1],
+					 &iph->saddr, 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;
 
@@ -56,34 +59,35 @@ tcp_conn_out_get(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, pptr[0],
-					  iph->daddr, 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, pptr[1],
-					  iph->saddr, pptr[0]);
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->daddr, pptr[1],
+					  &iph->saddr, 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, skb_network_header(skb), &iph);
 
-	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
+	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, skb->mark, iph.protocol, &iph.daddr,
+				     th->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -110,11 +114,21 @@ tcp_conn_schedule(struct sk_buff *skb,
 
 
 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))));
 }
@@ -125,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)))
@@ -133,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(skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/* Call application helper if needed */
@@ -141,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, cp->vaddr,
+		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;
@@ -155,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, cp->caddr,
-						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);
@@ -171,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)))
@@ -179,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(skb, pp))
+		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -190,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;
 
 	/*
@@ -198,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, cp->daddr,
+		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;
@@ -206,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, cp->daddr,
-						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;
@@ -216,21 +265,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. */
@@ -463,8 +534,13 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
 		     struct ip_vs_protocol *pp)
 {
 	struct tcphdr _tcph, *th;
+#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, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
+	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 e06020b..0ac6c74 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
  *
  */
 
@@ -24,8 +25,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;
@@ -35,61 +37,61 @@ udp_conn_in_get(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, pptr[0],
-				       iph->daddr, 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, pptr[1],
-				       iph->saddr, pptr[0]);
+		cp = ip_vs_conn_in_get(af, iph->protocol,
+				       &iph->daddr, pptr[1],
+				       &iph->saddr, pptr[0]);
 	}
 
 	return cp;
 }
 
-
 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]);
+		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, pptr[1],
-					iph->saddr, pptr[0]);
+		cp = ip_vs_conn_out_get(af, iph->protocol,
+					&iph->daddr, pptr[1],
+					&iph->saddr, pptr[0]);
 	}
 
 	return cp;
 }
 
-
 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;
 
-	uh = skb_header_pointer(skb, ip_hdrlen(skb),
-				sizeof(_udph), &_udph);
+	ip_vs_fill_iphdr(af, 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, skb->mark, iph.protocol, &iph.daddr,
+				     uh->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -114,25 +116,42 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
 	return 1;
 }
 
-
 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;
 }
 
+
 static int
 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)))
@@ -140,7 +159,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(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -150,7 +169,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;
 
 	/*
@@ -158,7 +177,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(cp->af, udph, &cp->daddr, &cp->vaddr,
 				     cp->dport, cp->vport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -166,9 +185,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, cp->caddr,
-						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",
@@ -184,7 +213,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)))
@@ -192,7 +228,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(cp->af, skb, pp))
 			return 0;
 
 		/*
@@ -203,7 +239,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;
 
 	/*
@@ -211,7 +247,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(cp->af, udph, &cp->vaddr, &cp->daddr,
 				     cp->vport, cp->dport);
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
@@ -219,9 +255,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, cp->daddr,
-						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;
@@ -231,10 +277,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)
@@ -246,15 +299,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. */
@@ -406,7 +472,6 @@ static void udp_exit(struct ip_vs_protocol *pp)
 {
 }
 
-
 struct ip_vs_protocol ip_vs_protocol_udp = {
 	.name =			"UDP",
 	.protocol =		IPPROTO_UDP,
-- 
1.5.4.5


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

* [PATCH RFC 09/24] IPVS: Add IPv6 Netfilter hooks and add/modify support functions
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (7 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6 Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support Julius Volz
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add Netfilter hook entries for IPv6 and either extend the existing hook
functions to handle both v4 and v6, or where it seems easier, add new ones
for v6. Also adapt/add some helper functions for v6.

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

 2 files changed, 437 insertions(+), 61 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 9ba9ee7..352807b 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -901,7 +901,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_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 63c08c4..99e8938 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;
@@ -408,20 +418,27 @@ 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;
+	int unicast;
+	ip_vs_fill_iphdr(svc->af, 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;
 	}
 
+#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) == RTN_UNICAST)) {
+	if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
 		int ret, cs;
 		struct ip_vs_conn *cp;
 
@@ -429,9 +446,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(svc->af, iph.protocol,
+				    &iph.saddr, pptr[0],
+				    &iph.daddr, pptr[1],
 				    0, 0,
 				    IP_VS_CONN_F_BYPASS,
 				    NULL);
@@ -473,7 +490,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;
 }
 
@@ -512,6 +536,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
@@ -526,14 +558,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);
 	}
 
@@ -560,6 +592,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,
@@ -572,6 +647,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 +703,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
 
 	offset += cih->ihl * 4;
 
+	ip_vs_fill_iphdr(AF_INET6, 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;
 
@@ -666,11 +743,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;
@@ -686,43 +868,67 @@ 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;
+	int af;
 
 	EnterFunction(11);
 
+	af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
+
 	if (skb->ipvs_property)
 		return NF_ACCEPT;
 
-	iph = ip_hdr(skb);
-	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;
-		iph = ip_hdr(skb);
-	}
+			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);
+	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) &&
-		     !pp->dont_defrag)) {
-		if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
-			return NF_STOLEN;
-		iph = ip_hdr(skb);
-	}
+#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, 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;
 
-	ihl = iph->ihl << 2;
+			ip_vs_fill_iphdr(af, 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, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		if (sysctl_ip_vs_nat_icmp_send &&
@@ -730,21 +936,31 @@ 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(af, iph.protocol,
+						      &iph.saddr,
+						      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);
+				if (iph.protocol != IPPROTO_TCP
+				    || !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;
 				}
 			}
@@ -756,14 +972,22 @@ 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 */
 	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
 		goto drop;
-	ip_hdr(skb)->saddr = cp->vaddr;
-	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
@@ -771,8 +995,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");
 
@@ -804,6 +1034,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 +1091,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
 
 	offset += cih->ihl * 4;
 
+	ip_vs_fill_iphdr(AF_INET6, 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;
 
@@ -888,6 +1120,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...
@@ -897,11 +1215,14 @@ 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;
+	int ret, restart, af;
+
+	af = (skb->protocol == __constant_htons(ETH_P_IP)) ? AF_INET : AF_INET6;
+
+	ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
 
 	/*
 	 *	Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@@ -916,31 +1237,28 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 		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, 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, skb, pp, &iph, iph.len, 0);
 
 	if (unlikely(!cp)) {
 		int v;
 
-		if (!pp->conn_schedule(skb, pp, &v, &cp))
+		if (!pp->conn_schedule(af, skb, pp, &v, &cp))
 			return v;
 	}
 
@@ -984,7 +1302,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]
@@ -1023,6 +1342,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,
@@ -1060,6 +1394,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] 59+ messages in thread

* [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (8 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 09/24] IPVS: Add IPv6 Netfilter hooks and add/modify support functions Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-27  6:28   ` Simon Horman
  2008-08-20 16:15 ` [PATCH RFC 11/24] IPVS: Add IPv6 xmit functions Julius Volz
                   ` (14 subsequent siblings)
  24 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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
IPv6 connections.

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

 1 files changed, 58 insertions(+), 43 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 99e8938..0f9a0a2 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -183,14 +183,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 */
+	__be16  dport;			/* destination port to forward */
+	union nf_inet_addr snet;	/* source network of the client, after masking */
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
 	/* Mask saddr with the netmask to adjust template granularity */
-	snet = iph->saddr & 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_BUF(6, "p-schedule: src %s:%u dest %s:%u "
 		      "mnet %s\n",
@@ -214,11 +221,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(svc->af, 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(svc->af, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
 			/*
@@ -238,18 +245,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(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr,
 						    ports[1],
-						    dest->addr, 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, 0,
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -268,12 +275,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(svc->af, IPPROTO_IP, &snet, 0,
+					     &fwmark, 0);
+		} else
+			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+					     &iph.daddr, 0);
 
 		if (!ct || !ip_vs_check_template(ct)) {
 			/*
@@ -292,18 +303,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, 0,
+			if (svc->fwmark) {
+				union nf_inet_addr fwmark = {
+					.all = { 0, 0, 0, htonl(svc->fwmark) }
+				};
+
+				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(iph->protocol,
-						    snet, 0,
-						    iph->daddr, 0,
-						    dest->addr, 0,
+			} else
+				ct = ip_vs_conn_new(svc->af, iph.protocol,
+						    &snet, 0,
+						    &iph.daddr, 0,
+						    &dest->addr, 0,
 						    IP_VS_CONN_F_TEMPLATE,
 						    dest);
 			if (ct == NULL)
@@ -320,10 +335,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, dport,
+	cp = ip_vs_conn_new(svc->af, iph.protocol,
+			    &iph.saddr, ports[0],
+			    &iph.daddr, ports[1],
+			    &dest->addr, dport,
 			    0,
 			    dest);
 	if (cp == NULL) {
@@ -352,12 +367,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;
 
@@ -387,10 +402,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, dest->port?dest->port:pptr[1],
+	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],
 			    0,
 			    dest);
 	if (cp == NULL)
-- 
1.5.4.5


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

* [PATCH RFC 11/24] IPVS: Add IPv6 xmit functions
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (9 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 12/24] IPVS: Extend functions for getting/creating connections Julius Volz
                   ` (13 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add xmit functions for IPv6 and a function ip_vs_bind_xmit_v6() for
binding them to a connection. Also add support for v6 to IP_VS_XMIT() and
the routing cache functions.

Much duplication here, since the new functions are copied from the old ones
and then modified for IPv6. Hard to efficiently factor out the common parts
though?

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

 3 files changed, 476 insertions(+), 13 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 352807b..565121e 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -857,6 +857,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
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index ea921dc..4eae6bf 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -369,6 +369,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)
 {
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 9892d4a..15c59aa 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);
@@ -71,7 +75,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 +84,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 +98,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;
 		}
 	}
@@ -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;
@@ -213,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)
@@ -264,7 +382,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");
@@ -276,7 +394,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;
@@ -292,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
@@ -423,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
@@ -467,7 +764,58 @@ 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;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	LeaveFunction(10);
+	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;
@@ -479,6 +827,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	LeaveFunction(10);
 	return NF_STOLEN;
 }
+#endif
 
 
 /*
@@ -540,7 +889,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;
@@ -557,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] 59+ messages in thread

* [PATCH RFC 12/24] IPVS: Extend functions for getting/creating connections
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (10 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 11/24] IPVS: Add IPv6 xmit functions Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 13/24] IPVS: Add IPv6 support to ip_vs_conn_hashkey() Julius Volz
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Extend functions for getting/creating connections and connection
templates with IPv6 support.

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

 2 files changed, 52 insertions(+), 28 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 565121e..c80eaec 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -641,11 +641,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)
@@ -656,9 +661,11 @@ 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);
 
 extern const char * ip_vs_state_name(__u16 proto, int state);
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 4eae6bf..1a6b9d8 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -187,20 +187,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 && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
+		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,13 +217,14 @@ 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_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
 		      ip_vs_proto_name(protocol),
@@ -233,20 +237,23 @@ struct ip_vs_conn *ip_vs_conn_in_get
 
 /* 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 && s_port==cp->cport &&
-		    d_port==cp->vport && d_addr==cp->vaddr &&
+		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;
@@ -273,7 +280,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 +289,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 && d_port == cp->cport &&
-		    s_port == cp->dport && s_addr == cp->daddr &&
+		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);
@@ -655,8 +665,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;
@@ -670,12 +681,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	   = caddr;
+	ip_vs_addr_copy(af, &cp->caddr, caddr);
 	cp->cport	   = cport;
-	cp->vaddr	   = vaddr;
+	ip_vs_addr_copy(af, &cp->vaddr, vaddr);
 	cp->vport	   = vport;
-	cp->daddr          = daddr;
+	ip_vs_addr_copy(af, &cp->daddr, daddr);
 	cp->dport          = dport;
 	cp->flags	   = flags;
 	spin_lock_init(&cp->lock);
@@ -702,7 +714,12 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport
 	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);
-- 
1.5.4.5


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

* [PATCH RFC 13/24] IPVS: Add IPv6 support to ip_vs_conn_hashkey()
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (11 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 12/24] IPVS: Extend functions for getting/creating connections Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 14/24] IPVS: Turn off FTP application helper for IPv6 Julius Volz
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add IPv6 support to ip_vs_conn_hashkey() by adding an 'af' argument and
update callers.

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

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

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 1a6b9d8..5e013c9 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -114,13 +114,21 @@ 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;
 }
 

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

* [PATCH RFC 14/24] IPVS: Turn off FTP application helper for IPv6
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (12 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 13/24] IPVS: Add IPv6 support to ip_vs_conn_hashkey() Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files Julius Volz
                   ` (10 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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 c1c758e..b4c7491 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] 59+ messages in thread

* [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (13 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 14/24] IPVS: Turn off FTP application helper for IPv6 Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 16/24] IPVS: Add function to determine if IPv6 address is local Julius Volz
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add support for procfs output of IPv6 service and connection entries.

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

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

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index efa34fb..e793d82 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1611,6 +1611,7 @@ static struct ctl_table vs_vars[] = {
 
 const struct ctl_path net_vs_ctl_path[] = {
 	{ .procname = "net", .ctl_name = CTL_NET, },
+	/* TODO IPv6: possible to move / duplicate this? */
 	{ .procname = "ipv4", .ctl_name = NET_IPV4, },
 	{ .procname = "vs", },
 	{ }
@@ -1751,15 +1752,26 @@ 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),
-				   ntohs(svc->port),
-				   svc->scheduler->name);
-		else
+		if (iter->table == ip_vs_svc_table) {
+			if (svc->af == AF_INET) {
+				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 (svc->af == AF_INET6) {
+#ifdef CONFIG_IP_VS_IPV6
+				seq_printf(seq, "%s  [" NIP6_FMT "]:%04X %s ",
+					   ip_vs_proto_name(svc->protocol),
+					   NIP6(svc->addr.in6),
+					   ntohs(svc->port),
+					   svc->scheduler->name);
+#endif
+			}
+		} 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",
@@ -1769,13 +1781,24 @@ 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), ntohs(dest->port),
-				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
-				   atomic_read(&dest->weight),
-				   atomic_read(&dest->activeconns),
-				   atomic_read(&dest->inactconns));
+			if (dest->af == AF_INET)
+				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
+			else 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));
+#endif
 		}
 	}
 	return 0;
-- 
1.5.4.5


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

* [PATCH RFC 16/24] IPVS: Add function to determine if IPv6 address is local
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (14 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries correctly Julius Volz
                   ` (8 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add __ip_vs_addr_is_local_v6() to find out if an IPv6 address belongs to a
local interface. This function is used 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 e793d82..f9db095 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
@@ -718,10 +739,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) == 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) {
@@ -770,9 +799,19 @@ 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);
-	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] 59+ messages in thread

* [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries correctly
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (15 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 16/24] IPVS: Add function to determine if IPv6 address is local Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 18/24] IPVS: Convert dest/service lookup functions Julius Volz
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Add support for IPv6 entry output to ip_vs_conn_seq_show() and
ip_vs_conn_sync_seq_show() proc/net file handlers.

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

 1 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 5e013c9..f0b848d 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -815,14 +815,26 @@ 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",
+		if (cp->af == AF_INET)
+			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);
+#ifdef CONFIG_IP_VS_IPV6
+		else
+			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);
+#endif
 	}
 	return 0;
 }
@@ -864,15 +876,28 @@ 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",
+		if (cp->af == AF_INET)
+			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);
+#ifdef CONFIG_IP_VS_IPV6
+		else
+			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);
+#endif
 	}
 	return 0;
 }
-- 
1.5.4.5


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

* [PATCH RFC 18/24] IPVS: Convert dest/service lookup functions
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (16 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries correctly Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers Julius Volz
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Convert the low-level dest and service lookup/hashing functions to deal
with IPv6 entries.

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

 2 files changed, 63 insertions(+), 31 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index c80eaec..28880e4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -807,7 +807,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)
 {
@@ -815,14 +816,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_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index f9db095..6127a97 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -303,11 +303,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;
 }
 
@@ -338,7 +346,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, 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 {
 		/*
@@ -385,16 +394,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 == vaddr)
+		if ((svc->af == af)
+		    && ip_vs_addr_equal(af, &svc->addr, vaddr)
 		    && (svc->port == vport)
 		    && (svc->protocol == protocol)) {
 			/* HIT */
@@ -410,7 +421,7 @@ __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;
@@ -419,7 +430,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;
@@ -430,7 +441,8 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__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;
 
@@ -439,14 +451,14 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 	/*
 	 *	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, 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, protocol, vaddr, vport);
 
 	if (svc == NULL
 	    && protocol == IPPROTO_TCP
@@ -456,7 +468,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, protocol, vaddr, FTPPORT);
 	}
 
 	if (svc == NULL
@@ -464,7 +476,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, protocol, vaddr, 0);
 	}
 
   out:
@@ -500,11 +512,18 @@ __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;
 
-	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+
+	return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
 		& IP_VS_RTAB_MASK;
 }
 
@@ -524,7 +543,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, dest->port);
+	hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
+
 	list_add(&dest->d_list, &ip_vs_rtable[hash]);
 
 	return 1;
@@ -551,7 +571,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;
@@ -560,11 +582,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 == daddr)
+		if ((dest->af == af)
+		    && ip_vs_addr_equal(af, &dest->addr, daddr)
 		    && (dest->port == dport)
 		    && ((dest->protocol == protocol) ||
 			dest->vfwmark)) {
@@ -582,7 +605,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;
 
@@ -590,7 +614,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 == daddr) && (dest->port == dport)) {
+		if ((dest->af == svc->af)
+		    && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
+		    && (dest->port == dport)) {
 			/* HIT */
 			return dest;
 		}
@@ -609,13 +635,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;
 
-	svc = ip_vs_service_get(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);
@@ -636,7 +663,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;
 
@@ -650,12 +678,13 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 			      IP_VS_DBG_ADDR(svc->af, &dest->addr),
 			      ntohs(dest->port),
 			      atomic_read(&dest->refcnt));
-		if (dest->addr == daddr &&
+		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 == svc->addr &&
+		     (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
 		      dest->vport == svc->port))) {
 			/* HIT */
 			return dest;
-- 
1.5.4.5


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

* [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (17 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 18/24] IPVS: Convert dest/service lookup functions Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-21  1:48   ` Simon Horman
  2008-08-20 16:15 ` [PATCH RFC 20/24] IPVS: Add validity checks when adding/editing v6 services Julius Volz
                   ` (5 subsequent siblings)
  24 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 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.

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

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

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 28880e4..144bcd5 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -521,6 +521,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 fa66824..bb0d426 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 7a6a319..5c37b73 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -540,6 +540,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,
 	.update_service =	ip_vs_lblc_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index c234e73..5ee5588 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -729,6 +729,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,
 	.update_service =	ip_vs_lblcr_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index b8670ec..d59fe8f 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -101,6 +101,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
 	.init_service =		ip_vs_lc_init_svc,
 	.done_service =		ip_vs_lc_done_svc,
 	.update_service =	ip_vs_lc_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index af277bc..0d3fff1 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -138,6 +138,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
 	.init_service =		ip_vs_nq_init_svc,
 	.done_service =		ip_vs_nq_done_svc,
 	.update_service =	ip_vs_nq_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index 358110d..cf41544 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -95,6 +95,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,
 	.done_service =		ip_vs_rr_done_svc,
 	.update_service =	ip_vs_rr_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 33d93b0..446d660 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -139,6 +139,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
 	.init_service =		ip_vs_sed_init_svc,
 	.done_service =		ip_vs_sed_done_svc,
 	.update_service =	ip_vs_sed_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 7b979e2..12f9ccc 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 76e3339..6d66459 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -127,6 +127,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
 	.init_service =		ip_vs_wlc_init_svc,
 	.done_service =		ip_vs_wlc_done_svc,
 	.update_service =	ip_vs_wlc_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 2f618dc..7ea92fe 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -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] 59+ messages in thread

* [PATCH RFC 20/24] IPVS: Add validity checks when adding/editing v6 services
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (18 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 21/24] IPVS: Only expose IPv4 entries through sockopt interface Julius Volz
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Check to see if the specified scheduler is supported with IPv6 and whether
the supplied prefix length is valid.

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

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

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6127a97..39ab7dc 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1160,6 +1160,19 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
 		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");
@@ -1247,6 +1260,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *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);
 
 	/*
-- 
1.5.4.5


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

* [PATCH RFC 21/24] IPVS: Only expose IPv4 entries through sockopt interface
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (19 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 20/24] IPVS: Add validity checks when adding/editing v6 services Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 22/24] IPVS: Add IPv6 support to genetlink interface Julius Volz
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Do not expose v6 services via the old sockopt interface and only count v6
services in ip_vs_num_services (which is only used to report the count to
userspace in the old interface).

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

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

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 39ab7dc..73150ce 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1209,7 +1209,10 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
 		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);
@@ -1337,7 +1340,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 */
@@ -2182,8 +2188,13 @@ __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));
 			ip_vs_copy_service(&entry, svc);
 			if (copy_to_user(&uptr->entrytable[count],
@@ -2197,8 +2208,12 @@ __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) {
+			if (svc->af != AF_INET)
+				continue;
+
 			if (count >= get->num_services)
 				goto out;
+
 			memset(&entry, 0, sizeof(entry));
 			ip_vs_copy_service(&entry, svc);
 			if (copy_to_user(&uptr->entrytable[count],
-- 
1.5.4.5


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

* [PATCH RFC 22/24] IPVS: Add IPv6 support to genetlink interface
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (20 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 21/24] IPVS: Only expose IPv4 entries through sockopt interface Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 23/24] IPVS: Small address/af usage fixups Julius Volz
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Allow adding IPv6 services in genetlink interface.

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

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

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 73150ce..f2caf56 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -2565,7 +2565,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);
@@ -2671,8 +2671,12 @@ 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;
 
-	/* For now, only support IPv4 */
-	if (nla_get_u16(nla_af) != AF_INET)
+	usvc->af = nla_get_u16(nla_af);
+#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] 59+ messages in thread

* [PATCH RFC 23/24] IPVS: Small address/af usage fixups
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (21 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 22/24] IPVS: Add IPv6 support to genetlink interface Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-20 16:15 ` [PATCH RFC 24/24] IPVS: Add notes about IPv6 changes Julius Volz
  2008-08-21  1:17 ` [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Simon Horman
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

Where this has not already been covered by other patches, fix up the code
to work with the new data structures and 'af' parameters.

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

 4 files changed, 158 insertions(+), 97 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index f0b848d..011d455 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -489,8 +489,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, cp->dport,
-				       cp->vaddr, 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_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index f2caf56..ba4d7c2 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -759,7 +759,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;
 
@@ -820,7 +820,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;
@@ -848,11 +848,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 = svc->addr;
 	dest->vport = svc->port;
 	dest->vfwmark = svc->fwmark;
-	dest->addr = udest->addr;
+	ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
 	dest->port = udest->port;
 
 	atomic_set(&dest->activeconns, 0);
@@ -877,10 +878,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;
 
@@ -897,10 +898,13 @@ 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, dport);
+
 	if (dest != NULL) {
 		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
 		return -EEXIST;
@@ -910,7 +914,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, dport);
 
 	if (dest != NULL) {
 		IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
@@ -985,10 +989,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);
@@ -1004,10 +1008,13 @@ 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, dport);
+
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
 		return -ENOENT;
@@ -1099,15 +1106,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, dport);
+
 	if (dest == NULL) {
 		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
 		return -ENOENT;
@@ -1142,7 +1149,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;
@@ -1184,8 +1192,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 = u->addr;
+	ip_vs_addr_copy(svc->af, &svc->addr, &u->addr);
 	svc->port = u->port;
 	svc->fwmark = u->fwmark;
 	svc->flags = u->flags;
@@ -1247,7 +1256,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;
@@ -2030,14 +2039,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;
@@ -2077,35 +2116,41 @@ 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.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)) {
+	    && (svc == NULL || svc->protocol != usvc.protocol)) {
 		ret = -ESRCH;
 		goto out_unlock;
 	}
@@ -2115,10 +2160,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);
@@ -2129,13 +2174,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;
@@ -2166,7 +2211,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));
@@ -2233,13 +2278,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;
@@ -2249,7 +2296,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);
@@ -2374,13 +2421,17 @@ 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)
@@ -2651,7 +2702,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];
@@ -2708,10 +2759,10 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *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,
-						  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);
@@ -2721,9 +2772,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);
 	}
@@ -2733,7 +2782,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);
@@ -2741,10 +2790,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,
-					   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)
@@ -2843,7 +2892,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];
@@ -2999,8 +3048,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;
 
@@ -3052,9 +3101,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, 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)) {
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index b4c7491..2abc34a 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 */
@@ -174,24 +174,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), 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, 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, 0,
-					      cp->vaddr, 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)
@@ -204,9 +204,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;
+		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);
 
@@ -251,7 +251,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;
 
@@ -307,12 +307,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;
@@ -322,16 +322,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.ip), 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));
+	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, htons(ntohs(cp->vport)-1),
-				      cp->daddr, 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_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index a652da2..40647ed 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) {
@@ -366,21 +366,28 @@ 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.
 			 * 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) {
@@ -389,10 +396,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] 59+ messages in thread

* [PATCH RFC 24/24] IPVS: Add notes about IPv6 changes
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (22 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 23/24] IPVS: Small address/af usage fixups Julius Volz
@ 2008-08-20 16:15 ` Julius Volz
  2008-08-21  1:17 ` [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Simon Horman
  24 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-20 16:15 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, vbusam, Julius Volz

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

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

 5 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 011d455..aa6f43b 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 0f9a0a2..5bb53c0 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 ba4d7c2..ec5e855 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -15,6 +15,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Changes:
+ * 	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 301b779..5c4b8f9 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_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] 59+ messages in thread

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
                   ` (23 preceding siblings ...)
  2008-08-20 16:15 ` [PATCH RFC 24/24] IPVS: Add notes about IPv6 changes Julius Volz
@ 2008-08-21  1:17 ` Simon Horman
  2008-08-21  9:59   ` Julius Volz
  24 siblings, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-21  1:17 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Aug 20, 2008 at 06:15:07PM +0200, Julius Volz wrote:
> Hi,
> 
> Ok, it might be the time to post these experimental IPv6 patches for IPVS
> again to get some comments and help. Since the last time, I've worked on
> reducing a lot of unnecessary code duplication, but some is still there
> where it was harder to get rid of. Also, we've implemented a genetlink
> interface (the first two patches in this series are exactly the v4
> version of that) and updated ipvsadm to work with it, so we do not have
> to break the existing sockopt userspace interface. Of course, there are
> also many other small fixes and changes since the last version.
> 
> - Full kernel patch in one file against davem's net-2.6:
> http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6.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)

Other than the packet format of the sync deamon, are there any
fundamental restrictions here? If we extended the sync daemon,
could it work? If so, perhaps we could rev the sync deamon protocol
and fix a few other kinks, like the handling of timeouts and the
general lack of extendability, at the same time.

> - 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!

Unfortunately (or fortunately depending on how you look at it),
I'm going to be away skiing for the next couple of days. Apologies
for the slow responses that will lead to.


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

* Re: [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers
  2008-08-20 16:15 ` [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers Julius Volz
@ 2008-08-21  1:48   ` Simon Horman
  2008-08-21 10:21     ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-21  1:48 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Aug 20, 2008 at 06:15:26PM +0200, Julius Volz wrote:
> 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.

I wonder if there are some spare bits inside the flags
member of ip_vs_scheduler that could be used for this purpose?

Otherwise, I'm fine with this, we can juggle things around
later to use the other bits in supports_ipv6 for other things
if and when the need arises.

Here is a version that applies against lvs-2.6

From: Julius Volz <juliusv@google.com>

IPVS: Add IPv6 support flag to schedulers

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.

Signed-off-by: Julius Volz <juliusv@google.com>
Signed-off-by: Simon Horman <horms@verge.net.au>

--- 

 include/net/ip_vs.h         |    3 +++
 net/ipv4/ipvs/ip_vs_dh.c    |    3 +++
 net/ipv4/ipvs/ip_vs_lblc.c  |    3 +++
 net/ipv4/ipvs/ip_vs_lblcr.c |    3 +++
 net/ipv4/ipvs/ip_vs_lc.c    |    3 +++
 net/ipv4/ipvs/ip_vs_nq.c    |    3 +++
 net/ipv4/ipvs/ip_vs_rr.c    |    3 +++
 net/ipv4/ipvs/ip_vs_sed.c   |    3 +++
 net/ipv4/ipvs/ip_vs_sh.c    |    3 +++
 net/ipv4/ipvs/ip_vs_wlc.c   |    3 +++
 net/ipv4/ipvs/ip_vs_wrr.c   |    3 +++
 11 files changed, 33 insertions(+)

b8c297df2a43ab6a2143f6ec5ccfb4943231e1c5
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index f591d7d..66ca986 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -475,6 +475,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 fa66824..bb0d426 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 d2a43aa..2d2287d 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 375a1ff..1da5e7f 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 2ad4e99..32e9ce7 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -83,6 +83,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 38adb1c..fa4cd7c 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -117,6 +117,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 f749291..f82719c 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -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 691a6a0..7d2f22f 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -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 7b979e2..12f9ccc 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 57b452b..8c596e7 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -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 2f618dc..7ea92fe 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -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,

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21  1:17 ` [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Simon Horman
@ 2008-08-21  9:59   ` Julius Volz
  2008-08-21 21:29     ` Simon Horman
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-21  9:59 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Thu, Aug 21, 2008 at 3:17 AM, Simon Horman <horms@verge.net.au> wrote:
> On Wed, Aug 20, 2008 at 06:15:07PM +0200, Julius Volz wrote:
>> 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)
>
> Other than the packet format of the sync deamon, are there any
> fundamental restrictions here? If we extended the sync daemon,
> could it work? If so, perhaps we could rev the sync deamon protocol
> and fix a few other kinks, like the handling of timeouts and the
> general lack of extendability, at the same time.

There shouldn't be any fundamental restrictions, it's just a piece of
the puzzle that I could easily leave out of the picture for now.

I haven't studied the sync daemon closely yet, but one thing I was
briefly wondering about was whether we should just blow up the
addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
(probably not acceptable, wasting too much bandwidth for v4 entries)
or how to send differently sized entries based on the IP version in a
clean way. But it sounds like you'd want to redesign a lot of that
anyways? I'm glad to help with anything, I just don't know this code
as well as you or Sven, but I'll study it more. Maybe you can share
some ideas on the extensibility you want to see?

>> Thanks for any comments!
>
> Unfortunately (or fortunately depending on how you look at it),
> I'm going to be away skiing for the next couple of days. Apologies
> for the slow responses that will lead to.

Have fun! And be careful, we need you to come back healthy :)

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers
  2008-08-21  1:48   ` Simon Horman
@ 2008-08-21 10:21     ` Julius Volz
  2008-08-21 13:23       ` Simon Horman
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-21 10:21 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam

On Thu, Aug 21, 2008 at 3:48 AM, Simon Horman wrote:
> On Wed, Aug 20, 2008 at 06:15:26PM +0200, Julius Volz wrote:
>> 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.
>
> I wonder if there are some spare bits inside the flags
> member of ip_vs_scheduler that could be used for this purpose?

Hm, there isn't any 'flags' member or similar in that struct...

> Otherwise, I'm fine with this, we can juggle things around
> later to use the other bits in supports_ipv6 for other things
> if and when the need arises.

Yes, then we could also rename it to 'flags' once needed.

> Here is a version that applies against lvs-2.6

Thanks, I guess I should start basing all of my IPVS patches on this
tree rather than net-2.6?

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers
  2008-08-21 10:21     ` Julius Volz
@ 2008-08-21 13:23       ` Simon Horman
  0 siblings, 0 replies; 59+ messages in thread
From: Simon Horman @ 2008-08-21 13:23 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Thu, Aug 21, 2008 at 12:21:39PM +0200, Julius Volz wrote:
> On Thu, Aug 21, 2008 at 3:48 AM, Simon Horman wrote:
> > On Wed, Aug 20, 2008 at 06:15:26PM +0200, Julius Volz wrote:
> >> 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.
> >
> > I wonder if there are some spare bits inside the flags
> > member of ip_vs_scheduler that could be used for this purpose?
> 
> Hm, there isn't any 'flags' member or similar in that struct...
> 
> > Otherwise, I'm fine with this, we can juggle things around
> > later to use the other bits in supports_ipv6 for other things
> > if and when the need arises.
> 
> Yes, then we could also rename it to 'flags' once needed.
> 
> > Here is a version that applies against lvs-2.6
> 
> Thanks, I guess I should start basing all of my IPVS patches on this
> tree rather than net-2.6?

That would make things slightly more convenient for me.
But I'm not the only fish in the sea :-)


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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-20 16:15 ` [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6 Julius Volz
@ 2008-08-21 13:29   ` Brian Haley
  2008-08-21 13:52     ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Brian Haley @ 2008-08-21 13:29 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, horms, kaber, vbusam

Julius Volz wrote:
> +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

I don't think you need the __constant_htons() here, just htons() - 
that's what tcp_ipv6.c does.

> +static void
> +ah_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_debug_packet_v6(pp, skb, offset, msg);
> +	else
> +#endif

htons()

> +static void
> +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))
> +		esp_debug_packet_v6(pp, skb, offset, msg);
> +	else
> +#endif

htons()

I think there's more in one of the other patches too.

So why can't you just create one ip_vs_debug_packet_v6() instead of 
these ah and esp ones which are identical?

-Brian

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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-21 13:29   ` Brian Haley
@ 2008-08-21 13:52     ` Julius Volz
  2008-08-21 14:08       ` Brian Haley
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-21 13:52 UTC (permalink / raw)
  To: Brian Haley; +Cc: netdev, lvs-devel, horms, kaber, vbusam

Hi,

On Thu, Aug 21, 2008 at 3:29 PM, Brian Haley <brian.haley@hp.com> wrote:
> Julius Volz wrote:
>>
>> +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
>
> I don't think you need the __constant_htons() here, just htons() - that's
> what tcp_ipv6.c does.

Thanks!

I guessed from the name and other uses that __constant_htons() is just
a version of htons() optimized for values that are constant at compile
time. Is this right? But htons() is fine too in any case.

>> +static void
>> +ah_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_debug_packet_v6(pp, skb, offset, msg);
>> +       else
>> +#endif
>
> htons()
>
>> +static void
>> +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))
>> +               esp_debug_packet_v6(pp, skb, offset, msg);
>> +       else
>> +#endif
>
> htons()
>
> I think there's more in one of the other patches too.
>
> So why can't you just create one ip_vs_debug_packet_v6() instead of these ah
> and esp ones which are identical?

If you look at the original files, the whole ip_vs_proto_ah.c and
ip_vs_proto_esp.c are 100% identical except for the protocol names /
constants :-/ So I stuck with this pattern for now. Maybe it would
make sense to join those two files in a change separate from the v6
functionality? There's already a lot of duplication in the existing
IPVS that could be removed...

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-21 13:52     ` Julius Volz
@ 2008-08-21 14:08       ` Brian Haley
  2008-08-21 14:55         ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Brian Haley @ 2008-08-21 14:08 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, horms, kaber, vbusam

Julius Volz wrote:
> I guessed from the name and other uses that __constant_htons() is just
> a version of htons() optimized for values that are constant at compile
> time. Is this right? But htons() is fine too in any case.

I think the __constant one is for initializations.  All I know is that 
someone (Stephen Hemminger?) always points this out in other patchsets, 
so I beat him to it.

>> So why can't you just create one ip_vs_debug_packet_v6() instead of these ah
>> and esp ones which are identical?
> 
> If you look at the original files, the whole ip_vs_proto_ah.c and
> ip_vs_proto_esp.c are 100% identical except for the protocol names /
> constants :-/ So I stuck with this pattern for now. Maybe it would
> make sense to join those two files in a change separate from the v6
> functionality? There's already a lot of duplication in the existing
> IPVS that could be removed...

I didn't look too closely, there's a lot of patches! :)  Doing it in a 
separate patch is probably a good idea though.

-Brian

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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-21 14:08       ` Brian Haley
@ 2008-08-21 14:55         ` Julius Volz
  2008-08-21 15:12           ` Brian Haley
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-21 14:55 UTC (permalink / raw)
  To: Brian Haley; +Cc: netdev, lvs-devel, horms, kaber, vbusam

On Thu, Aug 21, 2008 at 4:08 PM, Brian Haley <brian.haley@hp.com> wrote:
> Julius Volz wrote:
>>
>> I guessed from the name and other uses that __constant_htons() is just
>> a version of htons() optimized for values that are constant at compile
>> time. Is this right? But htons() is fine too in any case.
>
> I think the __constant one is for initializations.  All I know is that
> someone (Stephen Hemminger?) always points this out in other patchsets, so I
> beat him to it.

He :)

Still, I think my original interpretation was correct? It's always
used with constant values and there are many usages similar to this:

skb->protocol = __constant_htons(ETH_P_802_3);

Someone feel free to correct me.

>>> So why can't you just create one ip_vs_debug_packet_v6() instead of these
>>> ah
>>> and esp ones which are identical?
>>
>> If you look at the original files, the whole ip_vs_proto_ah.c and
>> ip_vs_proto_esp.c are 100% identical except for the protocol names /
>> constants :-/ So I stuck with this pattern for now. Maybe it would
>> make sense to join those two files in a change separate from the v6
>> functionality? There's already a lot of duplication in the existing
>> IPVS that could be removed...
>
> I didn't look too closely, there's a lot of patches! :)  Doing it in a

Yep, it's too big, I know :) And reworking the complete patch into a
sane series didn't really work out that well because everything is so
interdependent. Sometimes it might even be easier to look at the
complete, big patch...

> separate patch is probably a good idea though.

Yeah, should be easy. I'll look at it (if there is any interest).

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-21 14:55         ` Julius Volz
@ 2008-08-21 15:12           ` Brian Haley
  2008-08-21 15:28             ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Brian Haley @ 2008-08-21 15:12 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, horms, kaber, vbusam

Julius Volz wrote:
> Still, I think my original interpretation was correct? It's always
> used with constant values and there are many usages similar to this:
> 
> skb->protocol = __constant_htons(ETH_P_802_3);
> 
> Someone feel free to correct me.

I know it's a minor point, but look at tcp_ipv6.c:

         if (skb->protocol == htons(ETH_P_IP))
                 return tcp_v4_conn_request(sk, skb);

That's different from the code you quoted that's doing an assignment. 
__constant_htons() isn't used anywhere in an if() statement, although I 
did find a couple in the bonding driver that should be fixed.

-Brian

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

* Re: [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6
  2008-08-21 15:12           ` Brian Haley
@ 2008-08-21 15:28             ` Julius Volz
  0 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-21 15:28 UTC (permalink / raw)
  To: Brian Haley; +Cc: netdev, lvs-devel, horms, kaber, vbusam

On Thu, Aug 21, 2008 at 5:12 PM, Brian Haley <brian.haley@hp.com> wrote:
> Julius Volz wrote:
>>
>> Still, I think my original interpretation was correct? It's always
>> used with constant values and there are many usages similar to this:
>>
>> skb->protocol = __constant_htons(ETH_P_802_3);
>>
>> Someone feel free to correct me.
>
> I know it's a minor point, but look at tcp_ipv6.c:
>
>        if (skb->protocol == htons(ETH_P_IP))
>                return tcp_v4_conn_request(sk, skb);
>
> That's different from the code you quoted that's doing an assignment.
> __constant_htons() isn't used anywhere in an if() statement, although I did
> find a couple in the bonding driver that should be fixed.

Ok, maybe the problem with this is more what it says before the
definition of __constant_htons() in include/linux/byteorder.h?

----
/*
 * These helpers could be phased out over time as the base version
 * handles constant folding.
 */
---

Which is probably the reason why it shouldn't be used anymore? So
although it's probably doing the right thing already, I'll just change
it to htons() and everyone should be happy...

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21  9:59   ` Julius Volz
@ 2008-08-21 21:29     ` Simon Horman
  2008-08-21 22:01       ` Julius Volz
                         ` (2 more replies)
  0 siblings, 3 replies; 59+ messages in thread
From: Simon Horman @ 2008-08-21 21:29 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Thu, Aug 21, 2008 at 11:59:44AM +0200, Julius Volz wrote:
> On Thu, Aug 21, 2008 at 3:17 AM, Simon Horman <horms@verge.net.au> wrote:
> > On Wed, Aug 20, 2008 at 06:15:07PM +0200, Julius Volz wrote:
> >> 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)
> >
> > Other than the packet format of the sync deamon, are there any
> > fundamental restrictions here? If we extended the sync daemon,
> > could it work? If so, perhaps we could rev the sync deamon protocol
> > and fix a few other kinks, like the handling of timeouts and the
> > general lack of extendability, at the same time.
> 
> There shouldn't be any fundamental restrictions, it's just a piece of
> the puzzle that I could easily leave out of the picture for now.
> 
> I haven't studied the sync daemon closely yet, but one thing I was
> briefly wondering about was whether we should just blow up the
> addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
> (probably not acceptable, wasting too much bandwidth for v4 entries)
> or how to send differently sized entries based on the IP version in a
> clean way. But it sounds like you'd want to redesign a lot of that
> anyways? I'm glad to help with anything, I just don't know this code
> as well as you or Sven, but I'll study it more. Maybe you can share
> some ideas on the extensibility you want to see?

What I was thinking is that any change 
> 
> >> Thanks for any comments!
> >
> > Unfortunately (or fortunately depending on how you look at it),
> > I'm going to be away skiing for the next couple of days. Apologies
> > for the slow responses that will lead to.
> 
> Have fun! And be careful, we need you to come back healthy :)

Thanks.

Here are a few thoughts I have had in my breif overview of the code so far
- mainly just simple style things. If any of my comments are obviously
stupid, please just say so as I haven't got to the end of the series yet
and I'm sure some of my questions are answered in the code.

[PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h
[PATCH RFC 02/24] IPVS: Add genetlink interface implementation

* Already in lvs-2.6. Are there any changes?

[PATCH RFC 02/24] IPVS: Add genetlink interface implementation

* What is IP_VS = IPV6 ?

[PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses

* Indentation of af in struct ip_vs_conn seems inconsistent with other
  elements.

[PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures

* Use of p ? a : b construct in ip_vs_addr_equal() seems a bit aquard.
  How about

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_INET)
		return ipv6_addr_equal(&a->in6, &b->in6);
#endif
	return a->ip == b->ip;
}



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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21 21:29     ` Simon Horman
@ 2008-08-21 22:01       ` Julius Volz
  2008-08-27  5:59         ` Simon Horman
  2008-08-21 22:05       ` Simon Horman
  2008-08-27  7:17       ` Simon Horman
  2 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-21 22:01 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Thu, Aug 21, 2008 at 11:29 PM, Simon Horman <horms@verge.net.au> wrote:
> On Thu, Aug 21, 2008 at 11:59:44AM +0200, Julius Volz wrote:
>> There shouldn't be any fundamental restrictions, it's just a piece of
>> the puzzle that I could easily leave out of the picture for now.
>>
>> I haven't studied the sync daemon closely yet, but one thing I was
>> briefly wondering about was whether we should just blow up the
>> addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
>> (probably not acceptable, wasting too much bandwidth for v4 entries)
>> or how to send differently sized entries based on the IP version in a
>> clean way. But it sounds like you'd want to redesign a lot of that
>> anyways? I'm glad to help with anything, I just don't know this code
>> as well as you or Sven, but I'll study it more. Maybe you can share
>> some ideas on the extensibility you want to see?
>
> What I was thinking is that any change

Hm, I think you forgot to finish this sentence ;)

> Here are a few thoughts I have had in my breif overview of the code so far
> - mainly just simple style things. If any of my comments are obviously
> stupid, please just say so as I haven't got to the end of the series yet
> and I'm sure some of my questions are answered in the code.

Thanks for looking at this, no problem. I know it's a bit much to
digest, but I think there is no smaller part that I could post that is
useful in itself already.

> [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h
> [PATCH RFC 02/24] IPVS: Add genetlink interface implementation
>
> * Already in lvs-2.6. Are there any changes?

No, those are just exactly what I sent you before. I included them
because I was basing it on net-2.6.

Btw., David just announced that he opened net-next-2.6, so perhaps he
could pull the changes from your tree into that now?

> [PATCH RFC 02/24] IPVS: Add genetlink interface implementation
>
> * What is IP_VS = IPV6 ?

(IPV6 = y || IP_VS = IPV6) means that this option will only be visible
if either CONFIG_IPV6 is set to Y or if both CONFIG_IPV6 and
CONFIG_IP_VS are modules (if both are off, the whole submenu will be
hidden). So CONFIG_IPV6 has to be set at least as high as CONFIG_IP_VS
for this option to be visible.

> [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses
>
> * Indentation of af in struct ip_vs_conn seems inconsistent with other
>  elements.

Yeah, it's broken like this in the original and I kept it like that so
that things would still line up (because I didn't want to add noise by
touching the neighboring lines just for whitespace fixes). I could
just send a small whitespace fix to you before.

> [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures
>
> * Use of p ? a : b construct in ip_vs_addr_equal() seems a bit aquard.
>  How about
>
> 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_INET)
>                return ipv6_addr_equal(&a->in6, &b->in6);
> #endif
>        return a->ip == b->ip;
> }

Right, that is nicer! With AF_INET6 in that if-condition, of course.

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21 21:29     ` Simon Horman
  2008-08-21 22:01       ` Julius Volz
@ 2008-08-21 22:05       ` Simon Horman
  2008-08-22  9:56         ` Julius Volz
  2008-08-27  7:17       ` Simon Horman
  2 siblings, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-21 22:05 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On 金,  8月 22, 2008 at 07:29:50午前 +1000, Simon Horman wrote:
> On Thu, Aug 21, 2008 at 11:59:44AM +0200, Julius Volz wrote:
> > On Thu, Aug 21, 2008 at 3:17 AM, Simon Horman <horms@verge.net.au> wrote:
> > > On Wed, Aug 20, 2008 at 06:15:07PM +0200, Julius Volz wrote:
> > >> 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)
> > >
> > > Other than the packet format of the sync deamon, are there any
> > > fundamental restrictions here? If we extended the sync daemon,
> > > could it work? If so, perhaps we could rev the sync deamon protocol
> > > and fix a few other kinks, like the handling of timeouts and the
> > > general lack of extendability, at the same time.
> > 
> > There shouldn't be any fundamental restrictions, it's just a piece of
> > the puzzle that I could easily leave out of the picture for now.
> > 
> > I haven't studied the sync daemon closely yet, but one thing I was
> > briefly wondering about was whether we should just blow up the
> > addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
> > (probably not acceptable, wasting too much bandwidth for v4 entries)
> > or how to send differently sized entries based on the IP version in a
> > clean way. But it sounds like you'd want to redesign a lot of that
> > anyways? I'm glad to help with anything, I just don't know this code
> > as well as you or Sven, but I'll study it more. Maybe you can share
> > some ideas on the extensibility you want to see?
> 
> What I was thinking is that any change 

Sorry, I forgot to finish this sentance :-(

What I was thinking was that any change would introduce a
protocol incompatibility. However I think that there is
some room for small changes to be added using currently unsued
bits in ip_vs_sync_conn.flags. This could also be used to
allow syncryonising of timeouts (which is unrelated to IPv6).

So while my general feeling that the synchronisation protocol
is not as extendable as it should be stands. We can probably
work with the current protocol for now.




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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21 22:05       ` Simon Horman
@ 2008-08-22  9:56         ` Julius Volz
  2008-08-22 10:05           ` Graeme Fowler
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-22  9:56 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

2008/8/22 Simon Horman <horms@verge.net.au>:
> On 金,  8月 22, 2008 at 07:29:50午前 +1000, Simon Horman wrote:
>> On Thu, Aug 21, 2008 at 11:59:44AM +0200, Julius Volz wrote:
>> > On Thu, Aug 21, 2008 at 3:17 AM, Simon Horman <horms@verge.net.au> wrote:
>> > > On Wed, Aug 20, 2008 at 06:15:07PM +0200, Julius Volz wrote:
>> > >> 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)
>> > >
>> > > Other than the packet format of the sync deamon, are there any
>> > > fundamental restrictions here? If we extended the sync daemon,
>> > > could it work? If so, perhaps we could rev the sync deamon protocol
>> > > and fix a few other kinks, like the handling of timeouts and the
>> > > general lack of extendability, at the same time.
>> >
>> > There shouldn't be any fundamental restrictions, it's just a piece of
>> > the puzzle that I could easily leave out of the picture for now.
>> >
>> > I haven't studied the sync daemon closely yet, but one thing I was
>> > briefly wondering about was whether we should just blow up the
>> > addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
>> > (probably not acceptable, wasting too much bandwidth for v4 entries)
>> > or how to send differently sized entries based on the IP version in a
>> > clean way. But it sounds like you'd want to redesign a lot of that
>> > anyways? I'm glad to help with anything, I just don't know this code
>> > as well as you or Sven, but I'll study it more. Maybe you can share
>> > some ideas on the extensibility you want to see?
>>
>> What I was thinking is that any change
>
> Sorry, I forgot to finish this sentance :-(
>
> What I was thinking was that any change would introduce a
> protocol incompatibility. However I think that there is
> some room for small changes to be added using currently unsued
> bits in ip_vs_sync_conn.flags. This could also be used to
> allow syncryonising of timeouts (which is unrelated to IPv6).

There's also a '__u8 reserved' field at the beginning of that struct
which could be used. But in general, is it reasonable to expect both
nodes to use the same kernel version, which gets rid of the
extensibility problems? It's not really an ABI that can't be broken,
right?

> So while my general feeling that the synchronisation protocol
> is not as extendable as it should be stands. We can probably
> work with the current protocol for now.

Yes, without jumping through hoops, we have to probably break the
current protocol anyways for new features? Even if we designated
unused fields for new information, an old kernel will not look at them
/ fill them out, which limits the possibilities...

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22  9:56         ` Julius Volz
@ 2008-08-22 10:05           ` Graeme Fowler
  2008-08-22 10:49             ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Graeme Fowler @ 2008-08-22 10:05 UTC (permalink / raw)
  To: Julius Volz; +Cc: Simon Horman, netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Fri, 2008-08-22 at 11:56 +0200, Julius Volz wrote:
> There's also a '__u8 reserved' field at the beginning of that struct
> which could be used. But in general, is it reasonable to expect both
> nodes to use the same kernel version, which gets rid of the
> extensibility problems? It's not really an ABI that can't be broken,
> right?

I think from an operational (ie. end user) perspective, ABI breakage is
something to try to avoid but _not_ at all costs.

If it's possible to extend the sync daemon protocol by reusing the
existing code and ABI, all well and good; however if a fundamental
change is made which breaks the old sync daemon ABI then as long as it's
documented and we make sure that users know to have the same (or higher)
kernel versions on their directors then everyone wins.

> Yes, without jumping through hoops, we have to probably break the
> current protocol anyways for new features? Even if we designated
> unused fields for new information, an old kernel will not look at them
> / fill them out, which limits the possibilities...

I guess that as and when this change is made and gets into mainline
releases, Joe and I will have to have a mantra of "ensure your directors
are using the same kernel version" in response to queries on
lvs-users :)

Graeme


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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22 10:05           ` Graeme Fowler
@ 2008-08-22 10:49             ` Julius Volz
  2008-08-22 11:23               ` Sven Wegener
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-22 10:49 UTC (permalink / raw)
  To: Graeme Fowler
  Cc: Simon Horman, netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Fri, Aug 22, 2008 at 12:05 PM, Graeme Fowler <graeme@graemef.net> wrote:
> On Fri, 2008-08-22 at 11:56 +0200, Julius Volz wrote:
>> There's also a '__u8 reserved' field at the beginning of that struct
>> which could be used. But in general, is it reasonable to expect both
>> nodes to use the same kernel version, which gets rid of the
>> extensibility problems? It's not really an ABI that can't be broken,
>> right?
>
> I think from an operational (ie. end user) perspective, ABI breakage is
> something to try to avoid but _not_ at all costs.
>
> If it's possible to extend the sync daemon protocol by reusing the
> existing code and ABI, all well and good; however if a fundamental
> change is made which breaks the old sync daemon ABI then as long as it's
> documented and we make sure that users know to have the same (or higher)
> kernel versions on their directors then everyone wins.

Yeah, and it's not an ABI, it's a very specialized protocol between
two kernels, so the rules are less clear. However, I totally agree
with you that it's not convenient from the users' point of view.

>> Yes, without jumping through hoops, we have to probably break the
>> current protocol anyways for new features? Even if we designated
>> unused fields for new information, an old kernel will not look at them
>> / fill them out, which limits the possibilities...
>
> I guess that as and when this change is made and gets into mainline
> releases, Joe and I will have to have a mantra of "ensure your directors
> are using the same kernel version" in response to queries on
> lvs-users :)

He :) Imagine an old kernel on the backup receiving new messages and
not understanding them. How could we at least handle that situation
gracefully (without totally confusing the older kernel)? We'd need to
do it in a way that old features are still communicated in the same
way. E.g., v4-only connection syncs still use the same message format,
but once you use v6 entries, an unused flag or the 'reserved' field in
ip_vs_sync_conn is used. A v6 message would still confuse an older
kernel then, but a user would already notice that ipvsadm can't
configure the v6 services on the older kernel, so that's not too bad.

Anyways, these are just some thoughts. I'm unsure if we really need to
worry about this extension right now or if we could postpone it? At
least for me, it makes more sense to clean up the minimal set of IPv6
features first and then think about the more advanced/optional ones,
like the sync daemon.

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22 10:49             ` Julius Volz
@ 2008-08-22 11:23               ` Sven Wegener
  2008-08-22 12:14                 ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Sven Wegener @ 2008-08-22 11:23 UTC (permalink / raw)
  To: Julius Volz; +Cc: Graeme Fowler, Simon Horman, netdev, lvs-devel, kaber, vbusam

On Fri, 22 Aug 2008, Julius Volz wrote:

> On Fri, Aug 22, 2008 at 12:05 PM, Graeme Fowler <graeme@graemef.net> wrote:
> > On Fri, 2008-08-22 at 11:56 +0200, Julius Volz wrote:
> >> There's also a '__u8 reserved' field at the beginning of that struct
> >> which could be used. But in general, is it reasonable to expect both
> >> nodes to use the same kernel version, which gets rid of the
> >> extensibility problems? It's not really an ABI that can't be broken,
> >> right?
> >
> > I think from an operational (ie. end user) perspective, ABI breakage is
> > something to try to avoid but _not_ at all costs.
> >
> > If it's possible to extend the sync daemon protocol by reusing the
> > existing code and ABI, all well and good; however if a fundamental
> > change is made which breaks the old sync daemon ABI then as long as it's
> > documented and we make sure that users know to have the same (or higher)
> > kernel versions on their directors then everyone wins.
> 
> Yeah, and it's not an ABI, it's a very specialized protocol between
> two kernels, so the rules are less clear. However, I totally agree
> with you that it's not convenient from the users' point of view.
> 
> >> Yes, without jumping through hoops, we have to probably break the
> >> current protocol anyways for new features? Even if we designated
> >> unused fields for new information, an old kernel will not look at them
> >> / fill them out, which limits the possibilities...
> >
> > I guess that as and when this change is made and gets into mainline
> > releases, Joe and I will have to have a mantra of "ensure your directors
> > are using the same kernel version" in response to queries on
> > lvs-users :)
> 
> He :) Imagine an old kernel on the backup receiving new messages and
> not understanding them. How could we at least handle that situation
> gracefully (without totally confusing the older kernel)? We'd need to
> do it in a way that old features are still communicated in the same
> way. E.g., v4-only connection syncs still use the same message format,
> but once you use v6 entries, an unused flag or the 'reserved' field in
> ip_vs_sync_conn is used. A v6 message would still confuse an older
> kernel then, but a user would already notice that ipvsadm can't
> configure the v6 services on the older kernel, so that's not too bad.

If that's a problem, we can easily change the communication port and even 
completely redesign the protocol this way, without having old kernels 
getting confused about the data they get. We might lose the ability to 
sync between different versions, but in the end this is just the 
connection synchronziation and both systems should be running the same 
version. We could also keep the old communication port for some time, if 
that's really needed.

Sven

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22 11:23               ` Sven Wegener
@ 2008-08-22 12:14                 ` Julius Volz
  2008-08-23  9:20                   ` Graeme Fowler
  2008-08-27  6:09                   ` Simon Horman
  0 siblings, 2 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-22 12:14 UTC (permalink / raw)
  To: Sven Wegener
  Cc: Graeme Fowler, Simon Horman, netdev, lvs-devel, kaber, vbusam

On Fri, Aug 22, 2008 at 1:23 PM, Sven Wegener <sven.wegener@stealer.net> wrote:
>> He :) Imagine an old kernel on the backup receiving new messages and
>> not understanding them. How could we at least handle that situation
>> gracefully (without totally confusing the older kernel)? We'd need to
>> do it in a way that old features are still communicated in the same
>> way. E.g., v4-only connection syncs still use the same message format,
>> but once you use v6 entries, an unused flag or the 'reserved' field in
>> ip_vs_sync_conn is used. A v6 message would still confuse an older
>> kernel then, but a user would already notice that ipvsadm can't
>> configure the v6 services on the older kernel, so that's not too bad.
>
> If that's a problem, we can easily change the communication port and even
> completely redesign the protocol this way, without having old kernels
> getting confused about the data they get. We might lose the ability to
> sync between different versions, but in the end this is just the
> connection synchronziation and both systems should be running the same
> version. We could also keep the old communication port for some time, if
> that's really needed.

Yes, starting from scratch on another port sounds like a good idea.
Losing sync ability totally isn't as bad as confusing an older kernel
with new messages, so I hope it's not necessary to keep the old
baggage around?

Is there enough motivation for doing this though before having a
cleaned-up minimal v6 version without the sync daemon? This is where
I'm currently a bit stuck with... any help is appreciated :)

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22 12:14                 ` Julius Volz
@ 2008-08-23  9:20                   ` Graeme Fowler
  2008-08-23 15:22                     ` Joseph Mack NA3T
  2008-08-27  6:09                   ` Simon Horman
  1 sibling, 1 reply; 59+ messages in thread
From: Graeme Fowler @ 2008-08-23  9:20 UTC (permalink / raw)
  To: Julius Volz; +Cc: Sven Wegener, Simon Horman, netdev, lvs-devel, kaber, vbusam

On Fri, 2008-08-22 at 14:14 +0200, Julius Volz wrote:
> Yes, starting from scratch on another port sounds like a good idea.
> Losing sync ability totally isn't as bad as confusing an older kernel
> with new messages, so I hope it's not necessary to keep the old
> baggage around?

I agree - having a new sync daemon which can deal with v6 entries aswell
as v4 entries would be a good way to work; the legacy code can then be
retired at a later date with minimal end-user impact.

> Is there enough motivation for doing this though before having a
> cleaned-up minimal v6 version without the sync daemon? This is where
> I'm currently a bit stuck with... any help is appreciated :)

Well, as someone else mentioned on lvs-users recently "I couldn't code
my way out of a wet paper bag in C" so I'm not much help on that front,
however I feel that getting the minimal working feature set going first
and then adding the sync code later is probably a good way to proceed.

This also gives us a development timeline that we can offer to
interested parties, along the lines of:

2008-10 Minimal IPv6 functionality
2008-?? Full IPv6 functionality matching IPv4 features, no IPv6 sync
2009-?? Restructured sync daemon with full IPv4 and IPv6 support

Horms, Joe - do you agree that this is a good idea?

Graeme


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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-23  9:20                   ` Graeme Fowler
@ 2008-08-23 15:22                     ` Joseph Mack NA3T
  2008-08-23 16:31                       ` Graeme Fowler
  2008-08-23 23:07                       ` Julius Volz
  0 siblings, 2 replies; 59+ messages in thread
From: Joseph Mack NA3T @ 2008-08-23 15:22 UTC (permalink / raw)
  To: Graeme Fowler
  Cc: Julius Volz, Sven Wegener, Simon Horman, netdev, lvs-devel, kaber,
	vbusam

On Sat, 23 Aug 2008, Graeme Fowler wrote:

> This also gives us a development timeline that we can offer to
> interested parties, along the lines of:

we aren't a commercial shop. This is all being done by 
volunteers. In which case features arrive in the time and 
order that the coder(s) do it.

I don't think we should promise anything.

> 2008-10 Minimal IPv6 functionality
> 2008-?? Full IPv6 functionality matching IPv4 features, no IPv6 sync
> 2009-?? Restructured sync daemon with full IPv4 and IPv6 support
>
> Horms, Joe - do you agree that this is a good idea?

Joe

-- 
Joseph Mack NA3T EME(B,D), FM05lw North Carolina
jmack (at) wm7d (dot) net - azimuthal equidistant map
generator at http://www.wm7d.net/azproj.shtml
Homepage http://www.austintek.com/ It's GNU/Linux!

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-23 15:22                     ` Joseph Mack NA3T
@ 2008-08-23 16:31                       ` Graeme Fowler
  2008-08-24  2:13                         ` Joseph Mack NA3T
  2008-08-23 23:07                       ` Julius Volz
  1 sibling, 1 reply; 59+ messages in thread
From: Graeme Fowler @ 2008-08-23 16:31 UTC (permalink / raw)
  To: Joseph Mack NA3T
  Cc: Julius Volz, Sven Wegener, Simon Horman, netdev, lvs-devel, kaber,
	vbusam

On Sat, 2008-08-23 at 08:22 -0700, Joseph Mack NA3T wrote:
> we aren't a commercial shop. This is all being done by 
> volunteers. In which case features arrive in the time and 
> order that the coder(s) do it.

Yes, I know that.

> I don't think we should promise anything.

Well, it was just a suggestion. It'd be nice, I reckon, to be able to
say to people on lvs-users who ask us that "yes, this is currently being
worked on" at the very least. It might stop people bleating, as they
currently do (albeit rarely).

Graeme


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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-23 15:22                     ` Joseph Mack NA3T
  2008-08-23 16:31                       ` Graeme Fowler
@ 2008-08-23 23:07                       ` Julius Volz
  2008-08-24  1:40                         ` Joseph Mack NA3T
  1 sibling, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-23 23:07 UTC (permalink / raw)
  To: Joseph Mack NA3T
  Cc: Graeme Fowler, Sven Wegener, Simon Horman, netdev, lvs-devel,
	kaber, vbusam

On Sat, Aug 23, 2008 at 5:22 PM, Joseph Mack NA3T <jmack@wm7d.net> wrote:
> On Sat, 23 Aug 2008, Graeme Fowler wrote:
>
>> This also gives us a development timeline that we can offer to
>> interested parties, along the lines of:
>
> we aren't a commercial shop. This is all being done by volunteers. In which
> case features arrive in the time and order that the coder(s) do it.
>
> I don't think we should promise anything.

Right, we can only do our best, and even then we can't make
guarantuees about mainline inclusion...

>> 2008-10 Minimal IPv6 functionality

This is what we have as an experimental version right now. Meaning,
'works for us without problems, but not well tested or reviewed - any
help welcome'.

>> 2008-?? Full IPv6 functionality matching IPv4 features, no IPv6 sync

For fragmentation and other extension headers support, we would
probably need people with more knowledge of the rest of the IPv6 stack
to contribute. However, both features aren't common (especially
fragmentation with IPv6) in this situation, so missing them is not
likely to hurt a lot of people.

The other missing features are the 4 missing schedulers (DH, SH, LBLC,
LBLCR) and the FTP application helper.

>> 2009-?? Restructured sync daemon with full IPv4 and IPv6 support

This seems pretty doable once a protocol is decided upon and should be
done before the previous step, IMO.

Julius

-- 
Julius Volz
Corporate Operations - SysOps

Google Switzerland GmbH

Identification No.:
CH-020.4.028.116-1

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-23 23:07                       ` Julius Volz
@ 2008-08-24  1:40                         ` Joseph Mack NA3T
  0 siblings, 0 replies; 59+ messages in thread
From: Joseph Mack NA3T @ 2008-08-24  1:40 UTC (permalink / raw)
  To: Julius Volz
  Cc: Graeme Fowler, Sven Wegener, Simon Horman, netdev, lvs-devel,
	kaber, vbusam

On Sun, 24 Aug 2008, Julius Volz wrote:

> The other missing features are the 4 missing schedulers (DH, SH, LBLC,
> LBLCR) and the FTP application helper.

If it helps, the ipv4 ftp helper causes a lot of problems. 
People can't get it to work, because they can't follow the 
instructions. ftp is hard to secure and I think it should be 
done on a separate single machine. But if you have reasons 
to write an ipv6 ftp helper, don't let me stop you. I 
personally don't know important it is to have load balanced 
ftp. How does ftp.gnu.org and ftp.kernel.org handle their 
load? Since it's read-only, wouldn't failover handle it?

Now that I think if it. ibiblio.org, just up the street from 
me, runs on LVS. So maybe load balanced ftp is useful.

Joe

-- 
Joseph Mack NA3T EME(B,D), FM05lw North Carolina
jmack (at) wm7d (dot) net - azimuthal equidistant map
generator at http://www.wm7d.net/azproj.shtml
Homepage http://www.austintek.com/ It's GNU/Linux!

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-23 16:31                       ` Graeme Fowler
@ 2008-08-24  2:13                         ` Joseph Mack NA3T
  0 siblings, 0 replies; 59+ messages in thread
From: Joseph Mack NA3T @ 2008-08-24  2:13 UTC (permalink / raw)
  To: Graeme Fowler
  Cc: Julius Volz, Sven Wegener, Simon Horman, netdev, lvs-devel, kaber,
	vbusam

On Sat, 23 Aug 2008, Graeme Fowler wrote:

>> I don't think we should promise anything.
>
> Well, it was just a suggestion. It'd be nice, I reckon, to 
> be able to say to people on lvs-users who ask us that 
> "yes, this is currently being worked on" at the very 
> least.

If you say that then people will expect that it will 
eventually be released and will work, and be documented and 
we'll be able to help people get it working when it arrives.

A lot of stuff has been "worked on", but not tested or 
released. Horms has piles of stuff. Jason Stubbs has working 
code for lvs hooked into PREROUTING, a great step forward in 
my estimate, but has disappeared off the mailing list. If 
you tell people all this code is out there somewhere, being 
worked on, are you then prepared to tell them that you don't 
have the code, or that no-one's tested it, and there's no 
documentation and you haven't a clue how to set it up, and 
then try to help them install it and get it going? I'm quite 
prepared to believe that you can get Horms version of lvs 
hooked into FORWARD working and help people with it, but I 
can't. There's been more code written for LVS that's never 
seen the light of day, than has ever been released. I 
wouldn't want the LVS mailing list to become famous as a 
list of promises that are not kept.

Even code that's been tested by the author and released 
doesn't get used. The -SH scheduler sat untouched for years, 
because no-one knew how to use it. Someone spelunking the 
code, figured out how to configure it.

I still have no clue what LBLC does and it's been out for 
years.

> It might stop people bleating, as they currently do 
> (albeit rarely).

No-one, who is running LVS as part of his business, and who 
monitors the mailing list daily for at least a year, never 
helping anyone, waiting for a mention of the -SH scheduler, 
so that he remind everyone that the clueless LVS developers 
have not fixed his -SH problem (and that he has no intention 
of fixing it himself, or getting anyone under his command to 
fix it either) and if we don't do something pronto, he'll go 
to a commercial loadbalancer, is entitled to bleat.

Joe
-- 
Joseph Mack NA3T EME(B,D), FM05lw North Carolina
jmack (at) wm7d (dot) net - azimuthal equidistant map
generator at http://www.wm7d.net/azproj.shtml
Homepage http://www.austintek.com/ It's GNU/Linux!

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21 22:01       ` Julius Volz
@ 2008-08-27  5:59         ` Simon Horman
  0 siblings, 0 replies; 59+ messages in thread
From: Simon Horman @ 2008-08-27  5:59 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Fri, Aug 22, 2008 at 12:01:19AM +0200, Julius Volz wrote:
> On Thu, Aug 21, 2008 at 11:29 PM, Simon Horman <horms@verge.net.au> wrote:
> > On Thu, Aug 21, 2008 at 11:59:44AM +0200, Julius Volz wrote:
> >> There shouldn't be any fundamental restrictions, it's just a piece of
> >> the puzzle that I could easily leave out of the picture for now.
> >>
> >> I haven't studied the sync daemon closely yet, but one thing I was
> >> briefly wondering about was whether we should just blow up the
> >> addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr
> >> (probably not acceptable, wasting too much bandwidth for v4 entries)
> >> or how to send differently sized entries based on the IP version in a
> >> clean way. But it sounds like you'd want to redesign a lot of that
> >> anyways? I'm glad to help with anything, I just don't know this code
> >> as well as you or Sven, but I'll study it more. Maybe you can share
> >> some ideas on the extensibility you want to see?
> >
> > What I was thinking is that any change
> 
> Hm, I think you forgot to finish this sentence ;)
> 
> > Here are a few thoughts I have had in my breif overview of the code so far
> > - mainly just simple style things. If any of my comments are obviously
> > stupid, please just say so as I haven't got to the end of the series yet
> > and I'm sure some of my questions are answered in the code.
> 
> Thanks for looking at this, no problem. I know it's a bit much to
> digest, but I think there is no smaller part that I could post that is
> useful in itself already.
> 
> > [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h
> > [PATCH RFC 02/24] IPVS: Add genetlink interface implementation
> >
> > * Already in lvs-2.6. Are there any changes?
> 
> No, those are just exactly what I sent you before. I included them
> because I was basing it on net-2.6.
> 
> Btw., David just announced that he opened net-next-2.6, so perhaps he
> could pull the changes from your tree into that now?

Yes, I hope so.

> > [PATCH RFC 02/24] IPVS: Add genetlink interface implementation
> >
> > * What is IP_VS = IPV6 ?
> 
> (IPV6 = y || IP_VS = IPV6) means that this option will only be visible
> if either CONFIG_IPV6 is set to Y or if both CONFIG_IPV6 and
> CONFIG_IP_VS are modules (if both are off, the whole submenu will be
> hidden). So CONFIG_IPV6 has to be set at least as high as CONFIG_IP_VS
> for this option to be visible.

Thanks, that was confusing me.

> > [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses
> >
> > * Indentation of af in struct ip_vs_conn seems inconsistent with other
> >  elements.
> 
> Yeah, it's broken like this in the original and I kept it like that so
> that things would still line up (because I didn't want to add noise by
> touching the neighboring lines just for whitespace fixes). I could
> just send a small whitespace fix to you before.

Ok

> > [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures
> >
> > * Use of p ? a : b construct in ip_vs_addr_equal() seems a bit aquard.
> >  How about
> >
> > 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_INET)
> >                return ipv6_addr_equal(&a->in6, &b->in6);
> > #endif
> >        return a->ip == b->ip;
> > }
> 
> Right, that is nicer! With AF_INET6 in that if-condition, of course.

Yeah, of course, I meant AF_INET6.

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-22 12:14                 ` Julius Volz
  2008-08-23  9:20                   ` Graeme Fowler
@ 2008-08-27  6:09                   ` Simon Horman
  2008-08-27 15:24                     ` Julius Volz
  1 sibling, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-27  6:09 UTC (permalink / raw)
  To: Julius Volz; +Cc: Sven Wegener, Graeme Fowler, netdev, lvs-devel, kaber, vbusam

On Fri, Aug 22, 2008 at 02:14:11PM +0200, Julius Volz wrote:
> On Fri, Aug 22, 2008 at 1:23 PM, Sven Wegener <sven.wegener@stealer.net> wrote:
> >> He :) Imagine an old kernel on the backup receiving new messages and
> >> not understanding them. How could we at least handle that situation
> >> gracefully (without totally confusing the older kernel)? We'd need to
> >> do it in a way that old features are still communicated in the same
> >> way. E.g., v4-only connection syncs still use the same message format,
> >> but once you use v6 entries, an unused flag or the 'reserved' field in
> >> ip_vs_sync_conn is used. A v6 message would still confuse an older
> >> kernel then, but a user would already notice that ipvsadm can't
> >> configure the v6 services on the older kernel, so that's not too bad.
> >
> > If that's a problem, we can easily change the communication port and even
> > completely redesign the protocol this way, without having old kernels
> > getting confused about the data they get. We might lose the ability to
> > sync between different versions, but in the end this is just the
> > connection synchronziation and both systems should be running the same
> > version. We could also keep the old communication port for some time, if
> > that's really needed.
> 
> Yes, starting from scratch on another port sounds like a good idea.
> Losing sync ability totally isn't as bad as confusing an older kernel
> with new messages, so I hope it's not necessary to keep the old
> baggage around?

That does sound like a nice idea. I think that is important that we don't
confuse older kernels. I guess the only time that ineroperability would be
important is when upgrading kernels, where you might want to take the
master ldirector down to upgrade it, then the standby.

> 
> Is there enough motivation for doing this though before having a
> cleaned-up minimal v6 version without the sync daemon? This is where
> I'm currently a bit stuck with... any help is appreciated :)

IPv6 without sync is fine by me. Its certainly much better than no IPv6.
Lets tackle sync a bit later.


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

* Re: [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support
  2008-08-20 16:15 ` [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support Julius Volz
@ 2008-08-27  6:28   ` Simon Horman
  2008-08-27 16:02     ` Julius Volz
  0 siblings, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-27  6:28 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Aug 20, 2008 at 06:15:17PM +0200, Julius Volz wrote:
> Convert ip_vs_schedule() and ip_vs_sched_persist() to support scheduling
> IPv6 connections.
> 
> Signed-off-by: Julius Volz <juliusv@google.com>
> 
>  1 files changed, 58 insertions(+), 43 deletions(-)
> 
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 99e8938..0f9a0a2 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -183,14 +183,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 */
> +	__be16  dport;			/* destination port to forward */
> +	union nf_inet_addr snet;	/* source network of the client, after masking */

Can you break the line above so that it is <= 80 columns wide?

	union nf_inet_addr snet;	/* source network of the client,
					 * after masking */

> +
> +	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
>  
>  	/* Mask saddr with the netmask to adjust template granularity */
> -	snet = iph->saddr & 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_BUF(6, "p-schedule: src %s:%u dest %s:%u "
>  		      "mnet %s\n",
> @@ -214,11 +221,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(svc->af, 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(svc->af, iph.protocol, &snet, 0,
> +					     &iph.daddr, 0);
>  
>  		if (!ct || !ip_vs_check_template(ct)) {
>  			/*
> @@ -238,18 +245,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(svc->af, iph.protocol,
> +						    &snet, 0,
> +						    &iph.daddr,
>  						    ports[1],
> -						    dest->addr, 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, 0,
> +				ct = ip_vs_conn_new(svc->af, iph.protocol,
> +						    &snet, 0,
> +						    &iph.daddr, 0,
> +						    &dest->addr, 0,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			if (ct == NULL)
> @@ -268,12 +275,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(svc->af, IPPROTO_IP, &snet, 0,
> +					     &fwmark, 0);
> +		} else
> +			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
> +					     &iph.daddr, 0);
>  
>  		if (!ct || !ip_vs_check_template(ct)) {
>  			/*
> @@ -292,18 +303,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, 0,
> +			if (svc->fwmark) {
> +				union nf_inet_addr fwmark = {
> +					.all = { 0, 0, 0, htonl(svc->fwmark) }
> +				};
> +
> +				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(iph->protocol,
> -						    snet, 0,
> -						    iph->daddr, 0,
> -						    dest->addr, 0,
> +			} else
> +				ct = ip_vs_conn_new(svc->af, iph.protocol,
> +						    &snet, 0,
> +						    &iph.daddr, 0,
> +						    &dest->addr, 0,
>  						    IP_VS_CONN_F_TEMPLATE,
>  						    dest);
>  			if (ct == NULL)
> @@ -320,10 +335,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, dport,
> +	cp = ip_vs_conn_new(svc->af, iph.protocol,
> +			    &iph.saddr, ports[0],
> +			    &iph.daddr, ports[1],
> +			    &dest->addr, dport,
>  			    0,
>  			    dest);
>  	if (cp == NULL) {
> @@ -352,12 +367,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;
>  
> @@ -387,10 +402,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, dest->port?dest->port:pptr[1],
> +	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],
>  			    0,
>  			    dest);
>  	if (cp == NULL)
> -- 
> 1.5.4.5

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-21 21:29     ` Simon Horman
  2008-08-21 22:01       ` Julius Volz
  2008-08-21 22:05       ` Simon Horman
@ 2008-08-27  7:17       ` Simon Horman
  2008-08-27 15:09         ` Julius Volz
  2 siblings, 1 reply; 59+ messages in thread
From: Simon Horman @ 2008-08-27  7:17 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

Here is a second round of thoughts after having gone through the whole series.


[PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output

* The #defines in ip_vs_dbg_addr seem a bit aquard.
  Could it be rearanged liks this?

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;
       return &buf[*idx - len];
}

* The comment "/* Only use from within IP_VS_DBG_BUF() macro */"
  should also mention usage inside IP_VS_ERR_BUF()

* If IP_VS_DBG_ADDR() is used more than once inside a single
  IP_VS_DBG_BUF() or IP_VS_ERR_BUF() call, won't ip_vs_dbg_buf
  be set to the value one of the  calls to IP_VS_DBG_ADDR,
  thus overwriting other calls and producing incorrect debugging
  output?

[PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files

* The netlink-aware ipvsadm code also seems to allow for dotted-quad
  representation of ipv4 addresses in proc. Is that representation used
  or planned to be used?

[PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries

* It might be cleaner to do:

#ifdef CONFIG_IP_VS_IPV6
	if (cp->af == AF_INET6)
		seq_printf ...
	else
#endif
		seq_printf ...


General

* You need to reorder and or merge patches such that after each
  patch is applied the code will build and run. It is ok for
  a patch to add code which isn't used until a later patch is applied.

* Where possible please make lines <= 80 columns wide


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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-27  7:17       ` Simon Horman
@ 2008-08-27 15:09         ` Julius Volz
  2008-08-27 23:48           ` Simon Horman
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-27 15:09 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Wed, Aug 27, 2008 at 9:17 AM, Simon Horman wrote:
> Here is a second round of thoughts after having gone through the whole series.

Thanks for wading through this!

> [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output
>
> * The #defines in ip_vs_dbg_addr seem a bit aquard.
>  Could it be rearanged liks this?
>
> 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;
>       return &buf[*idx - len];
> }

Yes, that looks nicer and more like the other cases!

> * The comment "/* Only use from within IP_VS_DBG_BUF() macro */"
>  should also mention usage inside IP_VS_ERR_BUF()

Right, thanks!

> * If IP_VS_DBG_ADDR() is used more than once inside a single
>  IP_VS_DBG_BUF() or IP_VS_ERR_BUF() call, won't ip_vs_dbg_buf
>  be set to the value one of the  calls to IP_VS_DBG_ADDR,
>  thus overwriting other calls and producing incorrect debugging
>  output?

No, the buffer can receive several strings (but it's limited in size,
so you have to be careful). An index to the current position in the
buffer is maintained in the 'idx' variable between multiple
IP_VS_DBG_ADDR calls used in the same outer macro.

In general, I'm a bit unsure if this kind of macro magic is acceptable
style, but it was the best way I could come up with to merge
alternating v4 and v6 output without too much code duplication.

> [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files
>
> * The netlink-aware ipvsadm code also seems to allow for dotted-quad
>  representation of ipv4 addresses in proc. Is that representation used
>  or planned to be used?

Good catch! No, I wasn't even aware of that feature in the new ipvsadm
(but now I see it). I think it should be removed because it is
effectively dead code (the existing v4 proc format shouldn't be
changed). Vince, do you agree?

> [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries
>
> * It might be cleaner to do:
>
> #ifdef CONFIG_IP_VS_IPV6
>        if (cp->af == AF_INET6)
>                seq_printf ...
>        else
> #endif
>                seq_printf ...

Yes, it's nicer this way around, I'll change that!

> General
>
> * You need to reorder and or merge patches such that after each
>  patch is applied the code will build and run. It is ok for
>  a patch to add code which isn't used until a later patch is applied.

Yes, I have found no nice way to achieve this yet :( At least not when
reworking the complete end result (one big patch) into smaller
patches, because there is so much interdependency and several logical
changes within the same hunks (or even lines). I might have to
manually do a step-by-step adding of the logical code features to get
this... I will try to work on that next.

> * Where possible please make lines <= 80 columns wide

Yes, I will check for that more strictly now (unless it really looks
nicer otherwise), thanks!

Julius

-- 
Julius Volz
Corporate Operations - SysOps

Google Switzerland GmbH

Identification No.:
CH-020.4.028.116-1

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-27  6:09                   ` Simon Horman
@ 2008-08-27 15:24                     ` Julius Volz
  2008-08-27 23:49                       ` Simon Horman
  0 siblings, 1 reply; 59+ messages in thread
From: Julius Volz @ 2008-08-27 15:24 UTC (permalink / raw)
  To: Simon Horman
  Cc: Sven Wegener, Graeme Fowler, netdev, lvs-devel, kaber, vbusam

On Wed, Aug 27, 2008 at 8:09 AM, Simon Horman <horms@verge.net.au> wrote:
> On Fri, Aug 22, 2008 at 02:14:11PM +0200, Julius Volz wrote:
>> On Fri, Aug 22, 2008 at 1:23 PM, Sven Wegener <sven.wegener@stealer.net> wrote:
>> >> He :) Imagine an old kernel on the backup receiving new messages and
>> >> not understanding them. How could we at least handle that situation
>> >> gracefully (without totally confusing the older kernel)? We'd need to
>> >> do it in a way that old features are still communicated in the same
>> >> way. E.g., v4-only connection syncs still use the same message format,
>> >> but once you use v6 entries, an unused flag or the 'reserved' field in
>> >> ip_vs_sync_conn is used. A v6 message would still confuse an older
>> >> kernel then, but a user would already notice that ipvsadm can't
>> >> configure the v6 services on the older kernel, so that's not too bad.
>> >
>> > If that's a problem, we can easily change the communication port and even
>> > completely redesign the protocol this way, without having old kernels
>> > getting confused about the data they get. We might lose the ability to
>> > sync between different versions, but in the end this is just the
>> > connection synchronziation and both systems should be running the same
>> > version. We could also keep the old communication port for some time, if
>> > that's really needed.
>>
>> Yes, starting from scratch on another port sounds like a good idea.
>> Losing sync ability totally isn't as bad as confusing an older kernel
>> with new messages, so I hope it's not necessary to keep the old
>> baggage around?
>
> That does sound like a nice idea. I think that is important that we don't
> confuse older kernels. I guess the only time that ineroperability would be
> important is when upgrading kernels, where you might want to take the
> master ldirector down to upgrade it, then the standby.

Good, that makes two votes for not keeping the old protocol in parallel? ;)

>> Is there enough motivation for doing this though before having a
>> cleaned-up minimal v6 version without the sync daemon? This is where
>> I'm currently a bit stuck with... any help is appreciated :)
>
> IPv6 without sync is fine by me. Its certainly much better than no IPv6.
> Lets tackle sync a bit later.

Ok, going for cleaning up and reworking more of the current IPv6 code then...

-- 
Julius Volz
Corporate Operations - SysOps

Google Switzerland GmbH

Identification No.:
CH-020.4.028.116-1

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

* Re: [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support
  2008-08-27  6:28   ` Simon Horman
@ 2008-08-27 16:02     ` Julius Volz
  0 siblings, 0 replies; 59+ messages in thread
From: Julius Volz @ 2008-08-27 16:02 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, vbusam

On Wed, Aug 27, 2008 at 8:28 AM, Simon Horman <horms@verge.net.au> wrote:
> On Wed, Aug 20, 2008 at 06:15:17PM +0200, Julius Volz wrote:
>> Convert ip_vs_schedule() and ip_vs_sched_persist() to support scheduling
>> IPv6 connections.
>>
>> Signed-off-by: Julius Volz <juliusv@google.com>
>>
>>  1 files changed, 58 insertions(+), 43 deletions(-)
>>
>> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
>> index 99e8938..0f9a0a2 100644
>> --- a/net/ipv4/ipvs/ip_vs_core.c
>> +++ b/net/ipv4/ipvs/ip_vs_core.c
>> @@ -183,14 +183,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 */
>> +     __be16  dport;                  /* destination port to forward */
>> +     union nf_inet_addr snet;        /* source network of the client, after masking */
>
> Can you break the line above so that it is <= 80 columns wide?

Sure! Same for all the other cases.

Julius

-- 
Julius Volz - Corporate Operations - SysOps

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

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-27 15:09         ` Julius Volz
@ 2008-08-27 23:48           ` Simon Horman
  0 siblings, 0 replies; 59+ messages in thread
From: Simon Horman @ 2008-08-27 23:48 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, vbusam, Sven Wegener

On Wed, Aug 27, 2008 at 05:09:52PM +0200, Julius Volz wrote:
> On Wed, Aug 27, 2008 at 9:17 AM, Simon Horman wrote:
> > Here is a second round of thoughts after having gone through the whole series.
> 
> Thanks for wading through this!
> 
> > [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output
> >
> > * The #defines in ip_vs_dbg_addr seem a bit aquard.
> >  Could it be rearanged liks this?
> >
> > 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;
> >       return &buf[*idx - len];
> > }
> 
> Yes, that looks nicer and more like the other cases!
> 
> > * The comment "/* Only use from within IP_VS_DBG_BUF() macro */"
> >  should also mention usage inside IP_VS_ERR_BUF()
> 
> Right, thanks!
> 
> > * If IP_VS_DBG_ADDR() is used more than once inside a single
> >  IP_VS_DBG_BUF() or IP_VS_ERR_BUF() call, won't ip_vs_dbg_buf
> >  be set to the value one of the  calls to IP_VS_DBG_ADDR,
> >  thus overwriting other calls and producing incorrect debugging
> >  output?
> 
> No, the buffer can receive several strings (but it's limited in size,
> so you have to be careful). An index to the current position in the
> buffer is maintained in the 'idx' variable between multiple
> IP_VS_DBG_ADDR calls used in the same outer macro.
>
> In general, I'm a bit unsure if this kind of macro magic is acceptable
> style, but it was the best way I could come up with to merge
> alternating v4 and v6 output without too much code duplication.

Thanks, I knew I was missing something obvious.  From a style point of
view, I'm not sure either, but it seems like a reasonable start. Perhaps a
slight enhancement would be to add a BUG_ON() to ip_vs_dbg_addr() which will
trigger if ip_vs_dbg_buf will overflow.

> > [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files
> >
> > * The netlink-aware ipvsadm code also seems to allow for dotted-quad
> >  representation of ipv4 addresses in proc. Is that representation used
> >  or planned to be used?
> 
> Good catch! No, I wasn't even aware of that feature in the new ipvsadm
> (but now I see it). I think it should be removed because it is
> effectively dead code (the existing v4 proc format shouldn't be
> changed). Vince, do you agree?

I only noticed it from fixing up the atio() problem in ipvsadm
that I posted a patch for the other day. Its not a big deal. But
it would be nice to eliminate dead code.

> > [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries
> >
> > * It might be cleaner to do:
> >
> > #ifdef CONFIG_IP_VS_IPV6
> >        if (cp->af == AF_INET6)
> >                seq_printf ...
> >        else
> > #endif
> >                seq_printf ...
> 
> Yes, it's nicer this way around, I'll change that!
> 
> > General
> >
> > * You need to reorder and or merge patches such that after each
> >  patch is applied the code will build and run. It is ok for
> >  a patch to add code which isn't used until a later patch is applied.
> 
> Yes, I have found no nice way to achieve this yet :( At least not when
> reworking the complete end result (one big patch) into smaller
> patches, because there is so much interdependency and several logical
> changes within the same hunks (or even lines). I might have to
> manually do a step-by-step adding of the logical code features to get
> this... I will try to work on that next.

I realise this is a pain but unfortunately it is needed.

> > * Where possible please make lines <= 80 columns wide
> 
> Yes, I will check for that more strictly now (unless it really looks
> nicer otherwise), thanks!

This is less critical, but thankfully easy :-)

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

* Re: [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS
  2008-08-27 15:24                     ` Julius Volz
@ 2008-08-27 23:49                       ` Simon Horman
  0 siblings, 0 replies; 59+ messages in thread
From: Simon Horman @ 2008-08-27 23:49 UTC (permalink / raw)
  To: Julius Volz; +Cc: Sven Wegener, Graeme Fowler, netdev, lvs-devel, kaber, vbusam

On Wed, Aug 27, 2008 at 05:24:53PM +0200, Julius Volz wrote:
> On Wed, Aug 27, 2008 at 8:09 AM, Simon Horman <horms@verge.net.au> wrote:
> > On Fri, Aug 22, 2008 at 02:14:11PM +0200, Julius Volz wrote:
> >> On Fri, Aug 22, 2008 at 1:23 PM, Sven Wegener <sven.wegener@stealer.net> wrote:
> >> >> He :) Imagine an old kernel on the backup receiving new messages and
> >> >> not understanding them. How could we at least handle that situation
> >> >> gracefully (without totally confusing the older kernel)? We'd need to
> >> >> do it in a way that old features are still communicated in the same
> >> >> way. E.g., v4-only connection syncs still use the same message format,
> >> >> but once you use v6 entries, an unused flag or the 'reserved' field in
> >> >> ip_vs_sync_conn is used. A v6 message would still confuse an older
> >> >> kernel then, but a user would already notice that ipvsadm can't
> >> >> configure the v6 services on the older kernel, so that's not too bad.
> >> >
> >> > If that's a problem, we can easily change the communication port and even
> >> > completely redesign the protocol this way, without having old kernels
> >> > getting confused about the data they get. We might lose the ability to
> >> > sync between different versions, but in the end this is just the
> >> > connection synchronziation and both systems should be running the same
> >> > version. We could also keep the old communication port for some time, if
> >> > that's really needed.
> >>
> >> Yes, starting from scratch on another port sounds like a good idea.
> >> Losing sync ability totally isn't as bad as confusing an older kernel
> >> with new messages, so I hope it's not necessary to keep the old
> >> baggage around?
> >
> > That does sound like a nice idea. I think that is important that we don't
> > confuse older kernels. I guess the only time that ineroperability would be
> > important is when upgrading kernels, where you might want to take the
> > master ldirector down to upgrade it, then the standby.
> 
> Good, that makes two votes for not keeping the old protocol in parallel? ;)

I'd like to keep compatibility if possible. But I think there is
a treshold of pain that we shouldn't cross. 

> >> Is there enough motivation for doing this though before having a
> >> cleaned-up minimal v6 version without the sync daemon? This is where
> >> I'm currently a bit stuck with... any help is appreciated :)
> >
> > IPv6 without sync is fine by me. Its certainly much better than no IPv6.
> > Lets tackle sync a bit later.
> 
> Ok, going for cleaning up and reworking more of the current IPv6 code then...

:-)

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

end of thread, other threads:[~2008-08-27 23:49 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-20 16:15 [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Julius Volz
2008-08-20 16:15 ` [PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
2008-08-20 16:15 ` [PATCH RFC 02/24] IPVS: Add genetlink interface implementation Julius Volz
2008-08-20 16:15 ` [PATCH RFC 03/24] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius Volz
2008-08-20 16:15 ` [PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses Julius Volz
2008-08-20 16:15 ` [PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures Julius Volz
2008-08-20 16:15 ` [PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output Julius Volz
2008-08-20 16:15 ` [PATCH RFC 07/24] IPVS: Convert existing debug uses to use new macros Julius Volz
2008-08-20 16:15 ` [PATCH RFC 08/24] IPVS: Make protocol handler functions support IPv6 Julius Volz
2008-08-21 13:29   ` Brian Haley
2008-08-21 13:52     ` Julius Volz
2008-08-21 14:08       ` Brian Haley
2008-08-21 14:55         ` Julius Volz
2008-08-21 15:12           ` Brian Haley
2008-08-21 15:28             ` Julius Volz
2008-08-20 16:15 ` [PATCH RFC 09/24] IPVS: Add IPv6 Netfilter hooks and add/modify support functions Julius Volz
2008-08-20 16:15 ` [PATCH RFC 10/24] IPVS: Extend scheduling functions for IPv6 support Julius Volz
2008-08-27  6:28   ` Simon Horman
2008-08-27 16:02     ` Julius Volz
2008-08-20 16:15 ` [PATCH RFC 11/24] IPVS: Add IPv6 xmit functions Julius Volz
2008-08-20 16:15 ` [PATCH RFC 12/24] IPVS: Extend functions for getting/creating connections Julius Volz
2008-08-20 16:15 ` [PATCH RFC 13/24] IPVS: Add IPv6 support to ip_vs_conn_hashkey() Julius Volz
2008-08-20 16:15 ` [PATCH RFC 14/24] IPVS: Turn off FTP application helper for IPv6 Julius Volz
2008-08-20 16:15 ` [PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files Julius Volz
2008-08-20 16:15 ` [PATCH RFC 16/24] IPVS: Add function to determine if IPv6 address is local Julius Volz
2008-08-20 16:15 ` [PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries correctly Julius Volz
2008-08-20 16:15 ` [PATCH RFC 18/24] IPVS: Convert dest/service lookup functions Julius Volz
2008-08-20 16:15 ` [PATCH RFC 19/24] IPVS: Add IPv6 support flag to schedulers Julius Volz
2008-08-21  1:48   ` Simon Horman
2008-08-21 10:21     ` Julius Volz
2008-08-21 13:23       ` Simon Horman
2008-08-20 16:15 ` [PATCH RFC 20/24] IPVS: Add validity checks when adding/editing v6 services Julius Volz
2008-08-20 16:15 ` [PATCH RFC 21/24] IPVS: Only expose IPv4 entries through sockopt interface Julius Volz
2008-08-20 16:15 ` [PATCH RFC 22/24] IPVS: Add IPv6 support to genetlink interface Julius Volz
2008-08-20 16:15 ` [PATCH RFC 23/24] IPVS: Small address/af usage fixups Julius Volz
2008-08-20 16:15 ` [PATCH RFC 24/24] IPVS: Add notes about IPv6 changes Julius Volz
2008-08-21  1:17 ` [PATCH RFC 00/24] IPVS: Add first IPv6 support to IPVS Simon Horman
2008-08-21  9:59   ` Julius Volz
2008-08-21 21:29     ` Simon Horman
2008-08-21 22:01       ` Julius Volz
2008-08-27  5:59         ` Simon Horman
2008-08-21 22:05       ` Simon Horman
2008-08-22  9:56         ` Julius Volz
2008-08-22 10:05           ` Graeme Fowler
2008-08-22 10:49             ` Julius Volz
2008-08-22 11:23               ` Sven Wegener
2008-08-22 12:14                 ` Julius Volz
2008-08-23  9:20                   ` Graeme Fowler
2008-08-23 15:22                     ` Joseph Mack NA3T
2008-08-23 16:31                       ` Graeme Fowler
2008-08-24  2:13                         ` Joseph Mack NA3T
2008-08-23 23:07                       ` Julius Volz
2008-08-24  1:40                         ` Joseph Mack NA3T
2008-08-27  6:09                   ` Simon Horman
2008-08-27 15:24                     ` Julius Volz
2008-08-27 23:49                       ` Simon Horman
2008-08-27  7:17       ` Simon Horman
2008-08-27 15:09         ` Julius Volz
2008-08-27 23:48           ` Simon Horman

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).