netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
@ 2008-07-21 13:02 Julius Volz
  2008-07-21 13:02 ` [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Julius Volz @ 2008-07-21 13:02 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, davem, tgraf, vbusam

This is the second version of the Generic Netlink interface for
IPVS. I integrated some comments from Thomas Graf, Patrick McHardy and
Yoshifuji Hideaki and changed a few things myself. The interface should
now follow existing Netlink conventions more closely and has been
tested without problems.

The two patches add a Generic Netlink interface to IPVS while keeping
the old get/setsockopt interface for userspace backwards compatibility.
The motivation for this is to have a more extensible interface for
future changes, such as the planned IPv6 support. ipvsadm is currently
being extended to support the new interface and features.

The ip_vs.h header change depends on this patch I sent previously:
"IPVS: Move userspace definitions to include/linux/ip_vs.h"
(this one looked good to Horms, can it go in?)

Julius

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

* [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h
  2008-07-21 13:02 [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Julius Volz
@ 2008-07-21 13:02 ` Julius Volz
  2008-07-21 13:02 ` [PATCHv2 2/2] IPVS: Add genetlink interface implementation Julius Volz
  2008-07-22  0:34 ` [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Simon Horman
  2 siblings, 0 replies; 12+ messages in thread
From: Julius Volz @ 2008-07-21 13:02 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, davem, tgraf, vbusam, Julius Volz

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

This depends on this patch I sent in previously:
"IPVS: Move userspace 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 2d4eb68..b53a124 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -245,4 +245,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] 12+ messages in thread

* [PATCHv2 2/2] IPVS: Add genetlink interface implementation
  2008-07-21 13:02 [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Julius Volz
  2008-07-21 13:02 ` [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
@ 2008-07-21 13:02 ` Julius Volz
  2008-07-24 23:58   ` Thomas Graf
  2008-07-22  0:34 ` [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Simon Horman
  2 siblings, 1 reply; 12+ messages in thread
From: Julius Volz @ 2008-07-21 13:02 UTC (permalink / raw)
  To: netdev, lvs-devel; +Cc: horms, kaber, davem, tgraf, 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, 877 insertions(+), 0 deletions(-)

diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 94c5767..76ceb1f 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -39,6 +39,7 @@
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/sock.h>
+#include <net/genetlink.h>
 
 #include <asm/uaccess.h>
 
@@ -2307,6 +2308,874 @@ 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 command attributes used in the first level */
+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_U32 },
+	[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_BINARY,
+					    .len = sizeof(struct ip_vs_flags) },
+	[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_SVC_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;
+	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;
+
+	mutex_lock(&__ip_vs_mutex);
+
+	cmd = info->genlhdr->cmd;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	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");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	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:
+	if (msg)
+		nlmsg_free(msg);
+out:
+	mutex_unlock(&__ip_vs_mutex);
+
+	return ret;
+}
+
+
+static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+	/* SET commands */
+	{
+		.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,
+	},
+};
+
+int 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;
+}
+
+void ip_vs_genl_unregister(void)
+{
+	genl_unregister_family(&ip_vs_genl_family);
+}
+
+/* End of Generic Netlink interface definitions */
+
 
 int ip_vs_control_init(void)
 {
@@ -2321,6 +3190,13 @@ int 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);
 
@@ -2357,6 +3233,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] 12+ messages in thread

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-21 13:02 [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Julius Volz
  2008-07-21 13:02 ` [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
  2008-07-21 13:02 ` [PATCHv2 2/2] IPVS: Add genetlink interface implementation Julius Volz
@ 2008-07-22  0:34 ` Simon Horman
  2008-07-22 16:43   ` Julius Volz
  2008-07-22 22:59   ` Vince Busam
  2 siblings, 2 replies; 12+ messages in thread
From: Simon Horman @ 2008-07-22  0:34 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, kaber, davem, tgraf, vbusam

On Mon, Jul 21, 2008 at 03:02:53PM +0200, Julius Volz wrote:
> This is the second version of the Generic Netlink interface for
> IPVS. I integrated some comments from Thomas Graf, Patrick McHardy and
> Yoshifuji Hideaki and changed a few things myself. The interface should
> now follow existing Netlink conventions more closely and has been
> tested without problems.
> 
> The two patches add a Generic Netlink interface to IPVS while keeping
> the old get/setsockopt interface for userspace backwards compatibility.
> The motivation for this is to have a more extensible interface for
> future changes, such as the planned IPv6 support. ipvsadm is currently
> being extended to support the new interface and features.

I'm not an expert on netlink, but these patches are looking good to me.
Is the user-space portion available somewhere?

> The ip_vs.h header change depends on this patch I sent previously:
> "IPVS: Move userspace definitions to include/linux/ip_vs.h"
> (this one looked good to Horms, can it go in?)

Yes, it can. I'll repost it with an Ack.

-- 
Horms


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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-22  0:34 ` [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Simon Horman
@ 2008-07-22 16:43   ` Julius Volz
  2008-07-22 22:59   ` Vince Busam
  1 sibling, 0 replies; 12+ messages in thread
From: Julius Volz @ 2008-07-22 16:43 UTC (permalink / raw)
  To: Simon Horman; +Cc: netdev, lvs-devel, kaber, davem, tgraf, vbusam

On Tue, Jul 22, 2008 at 2:34 AM, Simon Horman <horms@verge.net.au> wrote:
> I'm not an expert on netlink, but these patches are looking good to me.
> Is the user-space portion available somewhere?

It's not quite ready, but Vince can hopefully post a preview version
later today or tomorrow!

>> The ip_vs.h header change depends on this patch I sent previously:
>> "IPVS: Move userspace definitions to include/linux/ip_vs.h"
>> (this one looked good to Horms, can it go in?)
>
> Yes, it can. I'll repost it with an Ack.

Thanks!

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-22  0:34 ` [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Simon Horman
  2008-07-22 16:43   ` Julius Volz
@ 2008-07-22 22:59   ` Vince Busam
  2008-07-23 21:39     ` Vince Busam
  1 sibling, 1 reply; 12+ messages in thread
From: Vince Busam @ 2008-07-22 22:59 UTC (permalink / raw)
  To: Simon Horman; +Cc: Julius Volz, netdev, lvs-devel, kaber, davem, tgraf

Simon Horman wrote:
> I'm not an expert on netlink, but these patches are looking good to me.
> Is the user-space portion available somewhere?

http://sixpak.org/vince/google/ipvsadm-1.25-nl-1.tar.gz

This version will fall back to the old sockopt interface if netlink 
fails, and is thus fully backward compatible with old kernels.  The 
interface for libipvs did change slightly to allow for IPv6 addresses, 
which only work through netlink, and will return error if tried on the 
old sockopt interface.

Vince

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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-22 22:59   ` Vince Busam
@ 2008-07-23 21:39     ` Vince Busam
  2008-07-25  5:58       ` Simon Horman
  0 siblings, 1 reply; 12+ messages in thread
From: Vince Busam @ 2008-07-23 21:39 UTC (permalink / raw)
  To: Simon Horman; +Cc: Julius Volz, netdev, lvs-devel, kaber, davem, tgraf

Vince Busam wrote:
> Simon Horman wrote:
>> I'm not an expert on netlink, but these patches are looking good to me.
>> Is the user-space portion available somewhere?

Newer versions are available at
http://sixpak.org/vince/google/ipvsadm/

Vince

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

* Re: [PATCHv2 2/2] IPVS: Add genetlink interface implementation
  2008-07-21 13:02 ` [PATCHv2 2/2] IPVS: Add genetlink interface implementation Julius Volz
@ 2008-07-24 23:58   ` Thomas Graf
  2008-07-25 22:39     ` Julius Volz
  0 siblings, 1 reply; 12+ messages in thread
From: Thomas Graf @ 2008-07-24 23:58 UTC (permalink / raw)
  To: Julius Volz; +Cc: netdev, lvs-devel, horms, kaber, davem, vbusam

* Julius Volz <juliusv@google.com> 2008-07-21 15:02
> +static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
> +				 struct nlattr *nla, int full_entry)
> +{
> +	struct nlattr *attrs[IPVS_SVC_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))

Small typo here, attrs[] is defined with a length of IPVS_SVC_ATTR_MAX+1
while IPVS_DEST_ATTR_MAX is passed to to nla_parse_nested.


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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-23 21:39     ` Vince Busam
@ 2008-07-25  5:58       ` Simon Horman
  2008-07-25 22:36         ` Julius Volz
  0 siblings, 1 reply; 12+ messages in thread
From: Simon Horman @ 2008-07-25  5:58 UTC (permalink / raw)
  To: Vince Busam; +Cc: Julius Volz, netdev, lvs-devel, kaber, davem, tgraf

On Wed, Jul 23, 2008 at 02:39:10PM -0700, Vince Busam wrote:
> Vince Busam wrote:
>> Simon Horman wrote:
>>> I'm not an expert on netlink, but these patches are looking good to me.
>>> Is the user-space portion available somewhere?
>
> Newer versions are available at
> http://sixpak.org/vince/google/ipvsadm/

Great, thanks :-)

I have been playing with this a little today. I am able to configure
a virtual service and it does work. However clearing seems to be a bit
of a problem, as per the trace below.

I am using the following code:

linux-next-2.6 14b395e35d1afdd8019d11b92e28041fad591b71
+ [PATCH] IPVS: Move userspace definitions to include/linux/ip_vs.h
+ [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h
+ [PATCHv2 2/2] IPVS: Add genetlink interface implementation

I am running the code on i386 qemu running on an i386 machine.

My ipvsadm is ipvsadm-1.25-nl-2 (statically linked).
My libnl is Debian's libnl1 1.1-2 (rebuilt to provide a static version).

# ipvsadm -A -t 10.4.0.132:80
# ipvsadm -C
# ipvsadm -A -t 10.4.0.132:80
BUG: unable to handle kernel paging request at 44e30116
IP: [<c01e8b34>] ctrl_dumpfamily+0xa4/0xbc
*pde = 00000000 
Oops: 0000 [#1] 

Pid: 33, comm: ipvsadm Not tainted (2.6.26-kexec-05253-g14b395e-dirty #23)
EIP: 0060:[<c01e8b34>] EFLAGS: 00000212 CPU: 0
EIP is at ctrl_dumpfamily+0xa4/0xbc
EAX: c6f8b560 EBX: c02ee14c ECX: c02ee178 EDX: 44e300c6
ESI: c02ee108 EDI: 00000000 EBP: 00000010 ESP: c746dc48
 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
Process ipvsadm (pid: 33, ti=c746c000 task=c6f20a50 task.ti=c746c000)
Stack: 00000000 00000000 c6f8b560 c744e300 c744e260 c744e300 000000d0 c6faf000 
       c01e7073 00000020 0000000f ffffff97 c6f8b560 c744be00 c744e260 c6faf000 
       c6f8b560 00000000 c01e72c2 c6faf800 c0290ca0 c0290c60 c744e260 c01e83d2 
Call Trace:
 [<c01e7073>] netlink_dump+0x53/0x1bc
 [<c01e72c2>] netlink_dump_start+0xe6/0x118
 [<c01e83d2>] genl_rcv_msg+0x112/0x174
 [<c01e8a90>] ctrl_dumpfamily+0x0/0xbc
 [<c018cd2e>] copy_to_user+0x2a/0x38
 [<c01e82c0>] genl_rcv_msg+0x0/0x174
 [<c01e7450>] netlink_rcv_skb+0x38/0x7c
 [<c01e844d>] genl_rcv+0x19/0x24
 [<c01e6290>] netlink_unicast+0x168/0x1a4
 [<c01e6ad8>] netlink_sendmsg+0x1f8/0x260
 [<c01cf7a6>] sock_sendmsg+0xb2/0xd8
 [<c0121bf8>] autoremove_wake_function+0x0/0x30
 [<c016126e>] simple_lookup+0x2a/0x30
 [<c015064e>] real_lookup+0xa2/0xd4
 [<c018cd65>] copy_from_user+0x29/0x4c
 [<c018cd65>] copy_from_user+0x29/0x4c
 [<c01d6586>] verify_iovec+0x32/0x7c
 [<c01d0bcd>] sys_sendmsg+0x111/0x200
 [<c0133429>] buffered_rmqueue+0x115/0x1e0
 [<c0133643>] get_page_from_freelist+0x9f/0xf8
 [<c0133733>] __alloc_pages_internal+0x97/0x3dc
 [<c013c37f>] do_anonymous_page+0xa7/0xd0
 [<c013c95c>] handle_mm_fault+0x154/0x1a0
 [<c01d107e>] sys_socketcall+0x1a2/0x1ac
 [<c0103db2>] syscall_call+0x7/0xb
 =======================
Code: 48 08 8b 02 8b 50 2c 6a 01 ff 74 24 10 6a 02 89 d8 e8 39 f9 ff ff 83 c4 0c 85 c0 79 c2 8b 44 24 08 89 68 14 89 78 18 8b 54 24 0b <8b> 42 50 83 c4 10 5b 5e 5f 5d c3 90 c7 04 24 00 00 00 00 e9 68 
EIP: [<c01e8b34>] ctrl_dumpfamily+0xa4/0xbc SS:ESP 0068:c746dc48
---[ end trace fe319f25bee8d956 ]---
Segmentation fault
# 
# 

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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-25  5:58       ` Simon Horman
@ 2008-07-25 22:36         ` Julius Volz
  2008-07-25 23:29           ` Thomas Graf
  0 siblings, 1 reply; 12+ messages in thread
From: Julius Volz @ 2008-07-25 22:36 UTC (permalink / raw)
  To: Simon Horman; +Cc: Vince Busam, netdev, lvs-devel, kaber, davem, tgraf

On Fri, Jul 25, 2008 at 7:58 AM, Simon Horman <horms@verge.net.au> wrote:
> On Wed, Jul 23, 2008 at 02:39:10PM -0700, Vince Busam wrote:
>> Vince Busam wrote:
>>> Simon Horman wrote:
>>>> I'm not an expert on netlink, but these patches are looking good to me.
>>>> Is the user-space portion available somewhere?
>>
>> Newer versions are available at
>> http://sixpak.org/vince/google/ipvsadm/
>
> Great, thanks :-)
>
> I have been playing with this a little today. I am able to configure
> a virtual service and it does work. However clearing seems to be a bit
> of a problem, as per the trace below.
>
> I am using the following code:
>
> linux-next-2.6 14b395e35d1afdd8019d11b92e28041fad591b71
> + [PATCH] IPVS: Move userspace definitions to include/linux/ip_vs.h
> + [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h
> + [PATCHv2 2/2] IPVS: Add genetlink interface implementation
>
> I am running the code on i386 qemu running on an i386 machine.
>
> My ipvsadm is ipvsadm-1.25-nl-2 (statically linked).
> My libnl is Debian's libnl1 1.1-2 (rebuilt to provide a static version).
>
> # ipvsadm -A -t 10.4.0.132:80
> # ipvsadm -C
> # ipvsadm -A -t 10.4.0.132:80
> BUG: unable to handle kernel paging request at 44e30116
> IP: [<c01e8b34>] ctrl_dumpfamily+0xa4/0xbc
> *pde = 00000000
> Oops: 0000 [#1]
>
> Pid: 33, comm: ipvsadm Not tainted (2.6.26-kexec-05253-g14b395e-dirty #23)
> EIP: 0060:[<c01e8b34>] EFLAGS: 00000212 CPU: 0
> EIP is at ctrl_dumpfamily+0xa4/0xbc
> EAX: c6f8b560 EBX: c02ee14c ECX: c02ee178 EDX: 44e300c6
> ESI: c02ee108 EDI: 00000000 EBP: 00000010 ESP: c746dc48
>  DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
> Process ipvsadm (pid: 33, ti=c746c000 task=c6f20a50 task.ti=c746c000)
> Stack: 00000000 00000000 c6f8b560 c744e300 c744e260 c744e300 000000d0 c6faf000
>       c01e7073 00000020 0000000f ffffff97 c6f8b560 c744be00 c744e260 c6faf000
>       c6f8b560 00000000 c01e72c2 c6faf800 c0290ca0 c0290c60 c744e260 c01e83d2
> Call Trace:
>  [<c01e7073>] netlink_dump+0x53/0x1bc
>  [<c01e72c2>] netlink_dump_start+0xe6/0x118
>  [<c01e83d2>] genl_rcv_msg+0x112/0x174
>  [<c01e8a90>] ctrl_dumpfamily+0x0/0xbc
>  [<c018cd2e>] copy_to_user+0x2a/0x38
>  [<c01e82c0>] genl_rcv_msg+0x0/0x174
>  [<c01e7450>] netlink_rcv_skb+0x38/0x7c
>  [<c01e844d>] genl_rcv+0x19/0x24
>  [<c01e6290>] netlink_unicast+0x168/0x1a4
>  [<c01e6ad8>] netlink_sendmsg+0x1f8/0x260
>  [<c01cf7a6>] sock_sendmsg+0xb2/0xd8
>  [<c0121bf8>] autoremove_wake_function+0x0/0x30
>  [<c016126e>] simple_lookup+0x2a/0x30
>  [<c015064e>] real_lookup+0xa2/0xd4
>  [<c018cd65>] copy_from_user+0x29/0x4c
>  [<c018cd65>] copy_from_user+0x29/0x4c
>  [<c01d6586>] verify_iovec+0x32/0x7c
>  [<c01d0bcd>] sys_sendmsg+0x111/0x200
>  [<c0133429>] buffered_rmqueue+0x115/0x1e0
>  [<c0133643>] get_page_from_freelist+0x9f/0xf8
>  [<c0133733>] __alloc_pages_internal+0x97/0x3dc
>  [<c013c37f>] do_anonymous_page+0xa7/0xd0
>  [<c013c95c>] handle_mm_fault+0x154/0x1a0
>  [<c01d107e>] sys_socketcall+0x1a2/0x1ac
>  [<c0103db2>] syscall_call+0x7/0xb
>  =======================
> Code: 48 08 8b 02 8b 50 2c 6a 01 ff 74 24 10 6a 02 89 d8 e8 39 f9 ff ff 83 c4 0c 85 c0 79 c2 8b 44 24 08 89 68 14 89 78 18 8b 54 24 0b <8b> 42 50 83 c4 10 5b 5e 5f 5d c3 90 c7 04 24 00 00 00 00 e9 68
> EIP: [<c01e8b34>] ctrl_dumpfamily+0xa4/0xbc SS:ESP 0068:c746dc48
> ---[ end trace fe319f25bee8d956 ]---
> Segmentation fault
> #
> #

Thanks for reporting. I'm not in expert in interpreting these dumps,
but it seems like there is no IPVS code in the trace, only the Generic
Netlink functions? Thomas, is this correct?

I'm on vacation for two weeks now, but I am sure I tested exactly this
situation many times without an oops. Do you get this every time or
did this just happen once?

I use UML and not qemu, though.

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCHv2 2/2] IPVS: Add genetlink interface implementation
  2008-07-24 23:58   ` Thomas Graf
@ 2008-07-25 22:39     ` Julius Volz
  0 siblings, 0 replies; 12+ messages in thread
From: Julius Volz @ 2008-07-25 22:39 UTC (permalink / raw)
  To: Thomas Graf; +Cc: netdev, lvs-devel, horms, kaber, davem, vbusam

On Fri, Jul 25, 2008 at 1:58 AM, Thomas Graf <tgraf@suug.ch> wrote:
> * Julius Volz <juliusv@google.com> 2008-07-21 15:02
>> +static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
>> +                              struct nlattr *nla, int full_entry)
>> +{
>> +     struct nlattr *attrs[IPVS_SVC_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))
>
> Small typo here, attrs[] is defined with a length of IPVS_SVC_ATTR_MAX+1
> while IPVS_DEST_ATTR_MAX is passed to to nla_parse_nested.

Right, thanks for catching this! Will include this in the next
iteration after vacation...

Julius

-- 
Google Switzerland GmbH

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

* Re: [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface
  2008-07-25 22:36         ` Julius Volz
@ 2008-07-25 23:29           ` Thomas Graf
  0 siblings, 0 replies; 12+ messages in thread
From: Thomas Graf @ 2008-07-25 23:29 UTC (permalink / raw)
  To: Julius Volz; +Cc: Simon Horman, Vince Busam, netdev, lvs-devel, kaber, davem

* Julius Volz <juliusv@google.com> 2008-07-26 00:36
> On Fri, Jul 25, 2008 at 7:58 AM, Simon Horman <horms@verge.net.au> wrote:
> > BUG: unable to handle kernel paging request at 44e30116
> > IP: [<c01e8b34>] ctrl_dumpfamily+0xa4/0xbc

> Thanks for reporting. I'm not in expert in interpreting these dumps,
> but it seems like there is no IPVS code in the trace, only the Generic
> Netlink functions? Thomas, is this correct?

Yes, the crash happens in ctrl_dumpfamily() which is not related
to the ipvs interface at all. I'm not familar with the new ipvadm
tool yet and whether it dumps the controller table but even if
does, this smells like a ipvs dump is being continued by calling
the wrong cb function. I have a similar report which may be related.

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

end of thread, other threads:[~2008-07-25 23:29 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-21 13:02 [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Julius Volz
2008-07-21 13:02 ` [PATCHv2 1/2] IPVS: Add genetlink interface definitions to ip_vs.h Julius Volz
2008-07-21 13:02 ` [PATCHv2 2/2] IPVS: Add genetlink interface implementation Julius Volz
2008-07-24 23:58   ` Thomas Graf
2008-07-25 22:39     ` Julius Volz
2008-07-22  0:34 ` [PATCHv2 0/2] IPVS: Add Generic Netlink configuration interface Simon Horman
2008-07-22 16:43   ` Julius Volz
2008-07-22 22:59   ` Vince Busam
2008-07-23 21:39     ` Vince Busam
2008-07-25  5:58       ` Simon Horman
2008-07-25 22:36         ` Julius Volz
2008-07-25 23:29           ` Thomas Graf

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