diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/Config.in linux-2.4.26.user_sync//net/ipv4/ipvs/Config.in
--- linux-2.4.26//net/ipv4/ipvs/Config.in	2004-04-14 22:05:41.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/Config.in	2004-04-20 13:46:47.000000000 +0900
@@ -21,6 +21,8 @@
   dep_tristate '  never queue scheduling' CONFIG_IP_VS_NQ $CONFIG_IP_VS
   comment 'IPVS application helper'
   dep_tristate '  FTP protocol helper' CONFIG_IP_VS_FTP $CONFIG_IP_VS
+  comment 'IPVS synchronisation'
+  dep_tristate '  Allow synchronisation information to be sent to user-space' CONFIG_IP_VS_USER_SYNC $CONFIG_IP_VS
 fi
 
 endmenu
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/Makefile linux-2.4.26.user_sync//net/ipv4/ipvs/Makefile
--- linux-2.4.26//net/ipv4/ipvs/Makefile	2003-11-29 03:26:21.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/Makefile	2004-04-20 13:46:47.000000000 +0900
@@ -9,7 +9,7 @@
 
 O_TARGET :=	ipvs.o
 
-export-objs :=	ip_vs_core.o ip_vs_app.o
+export-objs :=	ip_vs_core.o ip_vs_app.o ip_vs_conn.o ip_vs_sync.o
 
 ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
 		ip_vs_app.o ip_vs_sync.o ip_vs_est.o
@@ -37,6 +37,10 @@
 # IPVS application helpers
 obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
 
+# Send synchronisation information to user-space
+obj-$(CONFIG_IP_VS_USER_SYNC) += ip_vs_user_sync.o
+
+
 include $(TOPDIR)/Rules.make
 
 ip_vs.o: $(ip_vs-objs)
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_app.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_app.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_app.c	2004-04-14 22:05:41.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_app.c	2004-04-20 13:46:47.000000000 +0900
@@ -483,7 +483,7 @@
 }
 
 
-int ip_vs_app_init(void)
+int __init ip_vs_app_init(void)
 {
 	int idx;
 
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_conn.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_conn.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_conn.c	2004-04-14 22:05:41.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_conn.c	2004-04-20 13:46:47.000000000 +0900
@@ -44,6 +44,7 @@
 
 #include <net/ip_vs.h>
 
+EXPORT_SYMBOL(ip_vs_conn_dump_to_sync);
 
 /*
  *  Connection hash table: for input and output packets lookups of IPVS
@@ -354,7 +355,7 @@
 
 static struct ip_vs_timeout_table *ip_vs_timeout_table = &vs_timeout_table;
 
-static const char * state_name_table[IP_VS_S_LAST+1] = {
+const char * state_name_table[IP_VS_S_LAST+1] = {
 	[IP_VS_S_NONE]          =	"NONE",
 	[IP_VS_S_ESTABLISHED]	=	"ESTABLISHED",
 	[IP_VS_S_SYN_SENT]	=	"SYN_SENT",
@@ -1512,6 +1513,31 @@
 }
 
 
+void ip_vs_conn_dump_to_sync(void)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+	volatile struct list_head *l,*e;
+
+	for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
+		/*
+		 *  Lock is actually needed in this loop.
+		 */
+		ct_read_lock_bh(idx);
+
+		l = &ip_vs_conn_tab[idx];
+		for (e=l->next; e!=l; e=e->next) {
+			cp = list_entry(e, struct ip_vs_conn, c_list);
+
+			IP_VS_DBG(4, "sync connection in bucket"
+					": bucket=%d e=%p cp=%p\n", idx, e, cp);
+			ip_vs_sync_conn(cp);
+		}
+		ct_read_unlock_bh(idx);
+	}
+}
+
+
 int ip_vs_conn_init(void)
 {
 	int idx;
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_core.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_core.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_core.c	2003-11-29 03:26:21.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_core.c	2004-04-20 13:46:47.000000000 +0900
@@ -1134,7 +1134,8 @@
 	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
 	    (cp->protocol != IPPROTO_TCP ||
 	     cp->state == IP_VS_S_ESTABLISHED) &&
-	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))
+	    (atomic_read(&cp->in_pkts) % IP_VS_SYNC_FREQUENCY 
+	     == IP_VS_SYNC_THRESHOLD))
 		ip_vs_sync_conn(cp);
 
 	ip_vs_conn_put(cp);
@@ -1247,10 +1248,17 @@
 		IP_VS_ERR("can't register forward_icmp hook.\n");
 		goto cleanup_postroutingops;
 	}
+	ret = ip_vs_sync_init();
+	if(ret < 0) {
+		IP_VS_ERR("can't init structures for syncronisation");
+		goto cleanup_forwardicmpops;
+	}
 
 	IP_VS_INFO("ipvs loaded.\n");
 	return ret;
 
+  cleanup_forwardicmpops:
+	nf_unregister_hook(&ip_vs_forward_icmp_ops);
   cleanup_postroutingops:
 	nf_unregister_hook(&ip_vs_post_routing_ops);
   cleanup_outops:
@@ -1276,6 +1284,7 @@
 	ip_vs_app_cleanup();
 	ip_vs_conn_cleanup();
 	ip_vs_control_cleanup();
+	ip_vs_sync_cleanup();
 	IP_VS_INFO("ipvs unloaded.\n");
 }
 
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_ctl.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_ctl.c	2004-04-14 22:05:41.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_ctl.c	2004-04-20 13:46:47.000000000 +0900
@@ -74,7 +74,9 @@
 static int sysctl_ip_vs_am_droprate = 10;
 int sysctl_ip_vs_cache_bypass = 0;
 int sysctl_ip_vs_expire_nodest_conn = 0;
-int sysctl_ip_vs_sync_threshold = 3;
+int sysctl_ip_vs_sync_threshold = IP_VS_SYNC_THRESHOLD_DEFAULT;
+int sysctl_ip_vs_sync_frequency = IP_VS_SYNC_FREQUENCY_DEFAULT;
+int sysctl_ip_vs_sync_msg_max_size = IP_VS_SYNC_MESG_MAX_SIZE_DEFAULT;
 int sysctl_ip_vs_nat_icmp_send = 0;
 
 #ifdef CONFIG_IP_VS_DEBUG
@@ -1437,6 +1439,12 @@
 	 {NET_IPV4_VS_SYNC_THRESHOLD, "sync_threshold",
 	  &sysctl_ip_vs_sync_threshold, sizeof(int), 0644, NULL,
 	  &proc_dointvec},
+	 {NET_IPV4_VS_SYNC_FREQUENCY, "sync_frequency",
+	  &sysctl_ip_vs_sync_frequency, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {NET_IPV4_VS_SYNC_MSG_MAX_SIZE, "sync_msg_max_size",
+	  &sysctl_ip_vs_sync_msg_max_size, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
 	 {NET_IPV4_VS_NAT_ICMP_SEND, "nat_icmp_send",
 	  &sysctl_ip_vs_nat_icmp_send, sizeof(int), 0644, NULL,
 	  &proc_dointvec},
@@ -1727,6 +1735,7 @@
 		ret = ip_vs_set_timeouts(urule);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
+		ip_vs_sync_table_register_default();
 		ret = start_sync_thread(urule->state, urule->mcast_ifn);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_sync.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_sync.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_sync.c	2004-04-14 22:05:41.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_sync.c	2004-04-20 13:47:07.000000000 +0900
@@ -30,69 +30,17 @@
 #define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */
 #define IP_VS_SYNC_PORT  8848          /* multicast port */
 
+EXPORT_SYMBOL(ip_vs_sync_table_register);
+EXPORT_SYMBOL(ip_vs_sync_table_register_default);
+EXPORT_SYMBOL(stop_sync_thread);
+EXPORT_SYMBOL(start_sync_thread);
+EXPORT_SYMBOL(dump_sync_thread);
+EXPORT_SYMBOL(ip_vs_process_message);
 
-/*
- *	IPVS sync connection entry
- */
-struct ip_vs_sync_conn {
-	__u8			reserved;
-
-	/* Protocol, addresses and port numbers */
-	__u8			protocol;       /* Which protocol (TCP/UDP) */
-	__u16			cport;
-	__u16                   vport;
-	__u16                   dport;
-	__u32                   caddr;          /* client address */
-	__u32                   vaddr;          /* virtual address */
-	__u32                   daddr;          /* destination address */
-
-	/* Flags and state transition */
-	__u16                   flags;          /* status flags */
-	__u16                   state;          /* state info */
-
-	/* The sequence options start here */
-};
-
-struct ip_vs_sync_conn_options {
-	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
-	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
-};
-
-#define IP_VS_SYNC_CONN_TIMEOUT (3*60*HZ)
-#define SIMPLE_CONN_SIZE  (sizeof(struct ip_vs_sync_conn))
-#define FULL_CONN_SIZE  \
-(sizeof(struct ip_vs_sync_conn) + sizeof(struct ip_vs_sync_conn_options))
-
-
-/*
-  The master mulitcasts messages to the backup load balancers in the
-  following format.
-
-       0                   1                   2                   3
-       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Count Conns  |   Reserved    |            Size               |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
-      |                    IPVS Sync Connection (1)                   |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                            .                                  |
-      |                            .                                  |
-      |                            .                                  |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
-      |                    IPVS Sync Connection (n)                   |
-      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-*/
-#define SYNC_MESG_MAX_SIZE      (24*50+4)
-struct ip_vs_sync_mesg {
-	__u8                    nr_conns;
-	__u8                    reserved;
-	__u16                   size;
-
-	/* ip_vs_sync_conn entries start here */
-};
+#define IP_VS_SYNC_TABLE_S_ACTIVE       0x01
+#define IP_VS_SYNC_TABLE_S_INACTIVE     0x00
 
+static ip_vs_sync_table_t *ip_vs_sync_table = NULL;
 
 struct ip_vs_sync_buff {
 	struct list_head        list;
@@ -145,14 +93,14 @@
 	if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC)))
 		return NULL;
 
-	if (!(sb->mesg=kmalloc(SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
+	if (!(sb->mesg=kmalloc(IP_VS_SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
 		kfree(sb);
 		return NULL;
 	}
 	sb->mesg->nr_conns = 0;
 	sb->mesg->size = 4;
 	sb->head = (unsigned char *)sb->mesg + 4;
-	sb->end = (unsigned char *)sb->mesg + SYNC_MESG_MAX_SIZE;
+	sb->end = (unsigned char *)sb->mesg + IP_VS_SYNC_MESG_MAX_SIZE;
 	sb->firstuse = jiffies;
 	return sb;
 }
@@ -203,8 +151,8 @@
 		}
 	}
 
-	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
-		SIMPLE_CONN_SIZE;
+	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? IP_VS_SYNC_FULL_CONN_SIZE :
+		IP_VS_SYNC_SIMPLE_CONN_SIZE;
 	m = curr_sb->mesg;
 	s = (struct ip_vs_sync_conn *)curr_sb->head;
 
@@ -229,7 +177,7 @@
 	curr_sb->head += len;
 
 	/* check if there is a space for next one */
-	if (curr_sb->head+FULL_CONN_SIZE > curr_sb->end) {
+	if (curr_sb->head+IP_VS_SYNC_FULL_CONN_SIZE > curr_sb->end) {
 		sb_queue_tail(curr_sb);
 		curr_sb = NULL;
 	}
@@ -245,7 +193,7 @@
  *      Process received multicast message and create the corresponding
  *      ip_vs_conn entries.
  */
-static void ip_vs_process_message(const char *buffer, const size_t buflen)
+void ip_vs_process_message(const char *buffer, const size_t buflen)
 {
 	struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
 	struct ip_vs_sync_conn *s;
@@ -255,12 +203,13 @@
 	int i;
 
 	if (buflen != m->size) {
-		IP_VS_ERR("bogus message\n");
+		IP_VS_ERR("bogus message (size)\n");
 		return;
 	}
 
 	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
 	for (i=0; i<m->nr_conns; i++) {
+
 		s = (struct ip_vs_sync_conn *)p;
 		cp = ip_vs_conn_in_get(s->protocol,
 				       s->caddr, s->cport,
@@ -286,16 +235,16 @@
 		if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) {
 			opt = (struct ip_vs_sync_conn_options *)&s[1];
 			memcpy(&cp->in_seq, opt, sizeof(*opt));
-			p += FULL_CONN_SIZE;
+			p += IP_VS_SYNC_FULL_CONN_SIZE;
 		} else
-			p += SIMPLE_CONN_SIZE;
+			p += IP_VS_SYNC_SIMPLE_CONN_SIZE;
 
 		atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold);
 		cp->timeout = IP_VS_SYNC_CONN_TIMEOUT;
 		ip_vs_conn_put(cp);
 
 		if (p > buffer+buflen) {
-			IP_VS_ERR("bogus message\n");
+			IP_VS_ERR("bogus message (buffer overrun)\n");
 			return;
 		}
 	}
@@ -417,6 +366,10 @@
 {
 	struct socket *sock;
 
+	if(!ip_vs_mcast_ifn) {
+		return(NULL);
+	}
+
 	/* First create a socket */
 	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
 		IP_VS_ERR("Error during creation of socket; terminating\n");
@@ -458,6 +411,10 @@
 {
 	struct socket *sock;
 
+	if(!ip_vs_mcast_ifn) {
+		return(NULL);
+	}
+
 	/* First create a socket */
 	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
 		IP_VS_ERR("Error during creation of socket; terminating\n");
@@ -557,35 +514,264 @@
 static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait);
 static int stop_sync = 0;
 
-static void sync_master_loop(void)
+static int dump_sync = 0;
+static spinlock_t dump_sync_lock;
+
+static int dump_sync_set_if_zero(int i) {
+	spin_lock_bh(&dump_sync_lock);
+	if (!dump_sync)
+		dump_sync = 1;
+	else
+		i = 0;
+	spin_unlock_bh(&dump_sync_lock);
+
+	return(i);
+}
+
+static int dump_sync_set(int i) {
+	spin_lock_bh(&dump_sync_lock);
+	dump_sync = i;
+	spin_unlock_bh(&dump_sync_lock);
+
+	return(i);
+}
+
+static int dump_sync_get(void) {
+	int result;
+
+	spin_lock_bh(&dump_sync_lock);
+	result = dump_sync;
+	spin_unlock_bh(&dump_sync_lock);
+
+	return(result);
+}
+
+/* Abstraction to allow replacement underlying syncronisation mechanisms */
+
+static int ip_vs_sync_send(struct socket *sock, 
+		const char *buffer, const size_t length, void **data) 
+{
+	return(ip_vs_send_async(sock, buffer, length));
+}
+
+static int ip_vs_sync_recv_loop(struct socket *sock, void **data) 
 {
+	char *buf;
+	int len;
+
+        if (!(buf=kmalloc(IP_VS_SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
+	                IP_VS_ERR("sync_backup_loop: kmalloc error\n");
+                return(-1);
+        }
+
+	for (;;) {
+		/* do you have data now? */
+		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
+			if ((len=ip_vs_receive(sock, buf,
+					       IP_VS_SYNC_MESG_MAX_SIZE))<=0) {
+				IP_VS_ERR("ip_vs_receive error\n");
+				break;
+			}
+			/* disable bottom half, because it accessed the data
+			   shared by softirq while getting/creating conns */
+			local_bh_disable();
+			ip_vs_process_message(buf, len);
+			local_bh_enable();
+		}
+
+		if (stop_sync)
+			break;
+
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ);
+		__set_current_state(TASK_RUNNING);
+	}
+
+	kfree(buf);
+
+	return(0);
+}
+
+
+static struct socket * ip_vs_sync_open_send(void **data)
+{
+	return(make_send_sock());
+}
+
+static struct socket * ip_vs_sync_open_recv(void **data)
+{
+	return(make_receive_sock());
+}
+
+static int ip_vs_sync_close(struct socket *sock, void **data)
+{
+	sock_release(sock);
+	return(0);
+}
+
+static int ip_vs_sync_done(struct socket *sock, void **data)
+{
+	return(0);
+}
+
+static __init ip_vs_sync_table_t *ip_vs_sync_table_create(void) 
+{
+	ip_vs_sync_table_t *table;
+
+	table = (ip_vs_sync_table_t *)kmalloc(sizeof(ip_vs_sync_table_t),
+			GFP_KERNEL);
+	if(!table) {
+		return(NULL);
+	}
+	memset(table, 0, sizeof(ip_vs_sync_table_t));
+	spin_lock_init(&table->lock);
+	return(table);
+}
+
+static __exit void ip_vs_sync_table_destroy(ip_vs_sync_table_t *table) 
+{
+	kfree(table);
+}
+
+int ip_vs_sync_table_register(ip_vs_sync_table_send_mesg_handler_t *send_mesg,
+		ip_vs_sync_table_recv_loop_handler_t *recv_loop,
+		ip_vs_sync_table_open_handler_t *open_send,
+		ip_vs_sync_table_open_handler_t *open_recv,
+		ip_vs_sync_table_close_handler_t *close_send,
+		ip_vs_sync_table_close_handler_t *close_recv,
+		ip_vs_sync_table_done_handler_t *done,
+		void *data) 
+{
+	spin_lock_bh(&ip_vs_sync_table->lock);
+
+	if(ip_vs_sync_table->state&IP_VS_SYNC_TABLE_S_ACTIVE) {
+		spin_unlock_bh(&ip_vs_sync_table->lock);
+		return(-EBUSY);
+	}
+
+	ip_vs_sync_table->send_mesg = send_mesg;
+	ip_vs_sync_table->recv_loop = recv_loop;
+	ip_vs_sync_table->open_send = open_send;
+	ip_vs_sync_table->open_recv = open_recv;
+	ip_vs_sync_table->close_send = close_send;
+	ip_vs_sync_table->close_recv = close_recv;
+	ip_vs_sync_table->done = done;
+	ip_vs_sync_table->data = data;
+	spin_unlock_bh(&ip_vs_sync_table->lock);
+
+	return(0);
+}
+
+void ip_vs_sync_table_register_default(void) 
+{
+	ip_vs_sync_table_register(ip_vs_sync_send, ip_vs_sync_recv_loop,
+			ip_vs_sync_open_send, ip_vs_sync_open_recv, 
+			ip_vs_sync_close, ip_vs_sync_close, 
+			ip_vs_sync_done, NULL);
+}
+
+static int ip_vs_sync_table_set_state(ip_vs_sync_table_t *table, int state) 
+{
+	int status = 0;
+
+	spin_lock_bh(&table->lock);
+	if(table->state != state) {
+		status = 1;
+		table->state = state;
+	}
+	spin_unlock_bh(&table->lock);
+
+	return(status);
+}
+
+#define IP_VS_SYNC_TABLE_SET_STATE(_state)  \
+	ip_vs_sync_table_set_state(ip_vs_sync_table, (_state))
+
+/* Just fake it if there is no function to call */
+#define IP_VS_SYNC_TABLE_SEND_MESG(_sock, _buffer, _length) \
+	( ( ip_vs_sync_table->send_mesg) ? \
+	  ip_vs_sync_table->send_mesg((_sock), (_buffer), (_length), \
+		  &ip_vs_sync_table->data) : 0)
+
+#define IP_VS_SYNC_TABLE_RECV_LOOP(_sock) \
+	( ( ip_vs_sync_table->recv_loop ) ? \
+	  ip_vs_sync_table->recv_loop((_sock), &ip_vs_sync_table->data) : 0 )
+
+#define IP_VS_SYNC_TABLE_OPEN_SEND() \
+	( ( ip_vs_sync_table->open_send ) ? \
+	  ip_vs_sync_table->open_send(&ip_vs_sync_table->data) : NULL )
+
+#define IP_VS_SYNC_TABLE_OPEN_RECV() \
+	( ( ip_vs_sync_table->open_recv ) ? \
+	  ip_vs_sync_table->open_recv(&ip_vs_sync_table->data) : NULL )
+
+#define IP_VS_SYNC_TABLE_CLOSE_SEND(_sock) \
+	( ( ip_vs_sync_table->close_send ) ? \
+	  ip_vs_sync_table->close_send((_sock), &ip_vs_sync_table->data) : 0 )
+
+#define IP_VS_SYNC_TABLE_CLOSE_RECV(_sock) \
+	( ( ip_vs_sync_table->close_recv ) ? \
+	  ip_vs_sync_table->close_recv((_sock), &ip_vs_sync_table->data) : 0 )
+
+#define IP_VS_SYNC_TABLE_DONE(_sock) \
+	( ( ip_vs_sync_table->done ) ? \
+	  ip_vs_sync_table->done((_sock), &ip_vs_sync_table->data) : 0 )
+
+
+static void sync_master_loop(wait_queue_t * wait)
+{
+	int status;
+	int do_dump;
 	struct socket *sock;
 	struct ip_vs_sync_buff *sb;
 	struct ip_vs_sync_mesg *m;
 
+
+	if(! IP_VS_SYNC_TABLE_SET_STATE(IP_VS_SYNC_TABLE_S_ACTIVE)) {
+		IP_VS_DBG(2, "Synchonisation table is in use, "
+				"can't start synchonisation process\n");
+		return;
+	}
+
 	/* create the sending multicast socket */
-	sock = make_send_sock();
+	sock = IP_VS_SYNC_TABLE_OPEN_SEND();
 	if (!sock)
-		return;
+		goto inactive;
 
 	for (;;) {
+		do_dump = dump_sync_get();
+
 		while ((sb=sb_dequeue())) {
 			m = sb->mesg;
-			if (ip_vs_send_async(sock, (char *)m,
-					     m->size) != m->size)
-				IP_VS_ERR("ip_vs_send_async error\n");
+			status = IP_VS_SYNC_TABLE_SEND_MESG(sock, (char *)m,
+					m->size);
+			if(status != m->size && status != 0) {
+				IP_VS_ERR("IP_VS_SYNC_TABLE_SEND_MESG"
+						" error 1\n");
+			}
 			ip_vs_sync_buff_release(sb);
 		}
 
-		/* check if entries stay in curr_sb for 2 seconds */
-		if ((sb = get_curr_sync_buff(2*HZ))) {
+		/* check if entries stay in curr_sb for a while */
+		if ( (sb = get_curr_sync_buff(2*HZ)) || (do_dump && 
+					(sb = get_curr_sync_buff(0)) && 
+					sb->mesg && sb->mesg->nr_conns)) {
 			m = sb->mesg;
-			if (ip_vs_send_async(sock, (char *)m,
-					     m->size) != m->size)
-				IP_VS_ERR("ip_vs_send_async error\n");
+			status = IP_VS_SYNC_TABLE_SEND_MESG(sock, (char *)m,
+					m->size);
+			if(status != m->size && status != 0) {
+				IP_VS_ERR("IP_VS_SYNC_TABLE_SEND_MESG"
+						" error 2\n");
+			}
 			ip_vs_sync_buff_release(sb);
 		}
 
+		if(do_dump) {
+			dump_sync_set(0);
+			IP_VS_SYNC_TABLE_DONE(sock);
+			IP_VS_DBG(2, "dumped\n");
+		}
+
 		if (stop_sync)
 			break;
 
@@ -605,54 +791,36 @@
 	}
 
 	/* release the sending multicast socket */
-	sock_release(sock);
+	IP_VS_SYNC_TABLE_CLOSE_SEND(sock);
+
+inactive:
+	/* Release the function table */
+	IP_VS_SYNC_TABLE_SET_STATE(IP_VS_SYNC_TABLE_S_INACTIVE);
 }
 
 
-static void sync_backup_loop(void)
+static void sync_backup_loop(wait_queue_t * wait)
 {
 	struct socket *sock;
-	char *buf;
-	int len;
 
-	if (!(buf=kmalloc(SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
-		IP_VS_ERR("sync_backup_loop: kmalloc error\n");
+	if(! IP_VS_SYNC_TABLE_SET_STATE(IP_VS_SYNC_TABLE_S_ACTIVE)) {
+		IP_VS_DBG(2, "Synchonisation table is in use, "
+				"can't start synchonisation process\n");
 		return;
 	}
 
 	/* create the receiving multicast socket */
-	sock = make_receive_sock();
+	sock = IP_VS_SYNC_TABLE_OPEN_RECV();
 	if (!sock)
 		goto out;
 
-	for (;;) {
-		/* do you have data now? */
-		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
-			if ((len=ip_vs_receive(sock, buf,
-					       SYNC_MESG_MAX_SIZE))<=0) {
-				IP_VS_ERR("receiving message error\n");
-				break;
-			}
-			/* disable bottom half, because it accessed the data
-			   shared by softirq while getting/creating conns */
-			local_bh_disable();
-			ip_vs_process_message(buf, len);
-			local_bh_enable();
-		}
-
-		if (stop_sync)
-			break;
-
-		__set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ);
-		__set_current_state(TASK_RUNNING);
-	}
+	IP_VS_SYNC_TABLE_RECV_LOOP(sock);
 
-	/* release the sending multicast socket */
-	sock_release(sock);
+	IP_VS_SYNC_TABLE_CLOSE_RECV(sock);
 
   out:
-	kfree(buf);
+	/* Release the function table */
+	IP_VS_SYNC_TABLE_SET_STATE(IP_VS_SYNC_TABLE_S_INACTIVE);
 }
 
 
@@ -692,10 +860,10 @@
 	complete((struct completion *)startup);
 
 	/* processing master/backup loop here */
-	if (state == IP_VS_STATE_MASTER)
-		sync_master_loop();
-	else if (state == IP_VS_STATE_BACKUP)
-		sync_backup_loop();
+	if (ip_vs_sync_state == IP_VS_STATE_MASTER)
+		sync_master_loop(&wait);
+	else if (ip_vs_sync_state == IP_VS_STATE_BACKUP)
+		sync_backup_loop(&wait);
 	else IP_VS_BUG();
 
 	remove_wait_queue(&sync_wait, &wait);
@@ -746,7 +914,9 @@
 		  sizeof(struct ip_vs_sync_conn));
 
 	ip_vs_sync_state = state;
-	strcpy(ip_vs_mcast_ifn, mcast_ifn);
+	if(mcast_ifn) {
+		strcpy(ip_vs_mcast_ifn, mcast_ifn);
+	}
 
   repeat:
 	if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
@@ -790,3 +960,42 @@
 
 	return 0;
 }
+
+
+int dump_sync_thread(void)
+{
+	IP_VS_INFO("requesting dump: sync thread %d ...\n", sync_pid);
+
+	if (!sync_pid)
+		return -ESRCH;
+
+	if(!dump_sync_set_if_zero(1)) {
+		 IP_VS_DBG(2, "dump already in progress\n");
+		return -EBUSY;
+	}
+
+	ip_vs_conn_dump_to_sync();
+
+	wake_up(&sync_wait);
+	schedule();
+
+	IP_VS_INFO("done\n");
+	return 0;
+}
+
+
+int __init ip_vs_sync_init(void) {
+	spin_lock_init(&dump_sync_lock);
+	ip_vs_sync_table = ip_vs_sync_table_create();
+	if(!ip_vs_sync_table) {
+		return(-1);
+	}
+
+	return(0);
+}
+
+int __exit ip_vs_sync_cleanup(void) {
+	stop_sync_thread();
+	ip_vs_sync_table_destroy(ip_vs_sync_table);
+	return(0);
+}
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_user_sync.c linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_user_sync.c
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_user_sync.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_user_sync.c	2004-04-20 13:47:07.000000000 +0900
@@ -0,0 +1,689 @@
+/**********************************************************************
+ * ip_vs_user_sync.c                                       September 2002
+ * Horms                                             horms@verge.net.au
+ *
+ * ip_vs_user_sync
+ * Netlink socket to communicate with LVS
+ * Copyright (C) 2002  Horms
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307  USA
+ **********************************************************************/
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#include <net/ip_vs.h>
+#include <net/ip_vs_user_sync.h>
+
+struct sock *ip_vs_user_sync = NULL;
+
+typedef struct {
+	__u32 pid;
+	__u16 flag;
+	__u16 state;
+	spinlock_t lock;
+} ip_vs_user_sync_peer_t;
+
+static ip_vs_user_sync_peer_t *ip_vs_user_sync_peer = NULL;
+
+#define IP_VS_USER_SYNC_RETRY 7
+
+#ifdef CONFIG_IP_VS_DEBUG
+
+#define IP_VS_USER_SYNC_HDR_DUMP(_level, _hdr) \
+	IP_VS_DBG((_level), "HDR\n" \
+		"  nlmsg_len=%u\n" \
+		"  nlmsg_type= 0x%04x\n" \
+		"  nlmsg_flags=0x%04x\n" \
+		"  nlmsg_seq=%u\n" \
+		"  nlmsg_pid=%u\n", \
+		(_hdr)->nlmsg_len, \
+		(_hdr)->nlmsg_type, \
+		(_hdr)->nlmsg_flags, \
+		(_hdr)->nlmsg_seq, \
+		(_hdr)->nlmsg_pid); \
+	if((_hdr)->nlmsg_type == NLMSG_ERROR) { \
+		struct nlmsgerr *_err = (struct nlmsgerr*) NLMSG_DATA((_hdr)); \
+		IP_VS_DBG((_level), " error=%d\n", _err->error); \
+	}
+
+
+#define IP_VS_USER_SYNC_SKB_DUMP(_level, _skb) \
+	IP_VS_DBG((_level), "SKB\n" \
+		"  len=%u\n" \
+		"  data_len=%u\n", \
+		(_skb)->len, \
+		(_skb)->data_len)
+
+#define IP_VS_USER_SYNC_PEER_DUMP(_level, _peer) \
+	IP_VS_DBG((_level), "PEER\n" \
+		"  pid=%u\n" \
+		"  flag= 0x%04x\n" \
+		"  state=0x%04x\n", \
+		(_peer)->pid, \
+		(_peer)->flag, \
+		(_peer)->state);
+
+#else /* CONFIG_IP_VS_DEBUG */
+
+#define IP_VS_USER_SYNC_HDR_DUMP(_level, _hdr) do {} while (0)
+#define IP_VS_USER_SYNC_SKB_DUMP(_level, _skb) do {} while (0)
+#define IP_VS_USER_SYNC_PEER_DUMP(_level, _peer) do {} while (0)
+
+#endif /* CONFIG_IP_VS_DEBUG */
+
+
+/**********************************************************************
+ *
+ * Peer information
+ *
+ **********************************************************************/
+
+static ip_vs_user_sync_peer_t *ip_vs_user_sync_peer_create(int *errp) 
+{
+	ip_vs_user_sync_peer_t *peer;
+
+	peer = kmalloc(sizeof(ip_vs_user_sync_peer_t), GFP_KERNEL);
+	if(!peer) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+
+	memset(peer, 0, sizeof(ip_vs_user_sync_peer_t));
+	spin_lock_init(&peer->lock);
+
+	return(peer);
+}
+
+static void ip_vs_user_sync_peer_destroy(ip_vs_user_sync_peer_t *peer)
+{
+	spin_lock_bh(&peer->lock);
+	peer->state|=IP_VS_USER_SYNC_TCP_S_TERMINATE;
+	spin_unlock_bh(&peer->lock);
+	kfree(peer);
+}
+
+#ifdef MODULE
+#define IP_VS_USER_SYNC_MOD_USE \
+	do { if(!MOD_IN_USE){ MOD_INC_USE_COUNT; } } while (0)
+#define IP_VS_USER_SYNC_MOD_FREE \
+	do { while(MOD_IN_USE) { MOD_DEC_USE_COUNT; } } while (0)
+#else
+#define IP_VS_USER_SYNC_MOD_USE
+#define IP_VS_USER_SYNC_MOD_FREE
+#endif
+
+#define __IP_VS_USER_SYNC_PEER_SET(_peer, _pid, _flag, _state) \
+	(_peer)->pid = (_pid); \
+	(_peer)->flag = (_flag); \
+	(_peer)->state = (_state);
+
+#define IP_VS_USER_SYNC_PEER_SET(_peer, _pid, _flag, _state) \
+	IP_VS_USER_SYNC_MOD_USE; \
+	__IP_VS_USER_SYNC_PEER_SET((_peer), (_pid), (_flag), (_state));
+
+#define IP_VS_USER_SYNC_PEER_RESET(_peer) \
+	IP_VS_USER_SYNC_MOD_FREE; \
+	__IP_VS_USER_SYNC_PEER_SET((_peer), 0, 0, 0);
+
+#define IP_VS_USER_SYNC_PEER_GET(_peer, _pid, _flag, _state) \
+	*(_pid) = (_peer)->pid; \
+	*(_flag) = (_peer)->flag; \
+	*(_state) = (_peer)->state;
+
+
+/**********************************************************************
+ *
+ * Netlink stuff
+ *
+ **********************************************************************/
+
+static int ip_vs_user_sync_event(struct notifier_block *this, 
+		unsigned long event, void *ptr)
+{
+	IP_VS_DBG(2, "Got an event (%ld)", event);
+	switch (event) {
+		case NETDEV_UP:
+		case NETDEV_DOWN:
+		case NETDEV_REBOOT:
+		case NETDEV_CHANGE:
+		case NETDEV_REGISTER:
+		case NETDEV_UNREGISTER:
+		case NETDEV_CHANGEMTU:
+		case NETDEV_CHANGEADDR:
+		case NETDEV_GOING_DOWN:
+		case NETDEV_CHANGENAME:
+		default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+
+struct notifier_block ip_vs_user_sync_notifier = {
+	ip_vs_user_sync_event,
+	NULL,
+	0
+};
+
+int ip_vs_user_sync_send(struct sock *ssk, const void *buf, 
+		__u32 len, __u16 type, __u16 flags, __u32 seq, __u32 pid)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *hdr;
+	void *data;
+	int status = -EMSGSIZE;
+	size_t data_len;
+
+	skb = alloc_skb(NLMSG_LENGTH(len), GFP_ATOMIC);
+	if(!skb) {
+		status = -ENOMEM;
+		goto nlmsg_failure;
+	}
+
+	data_len = len - NLMSG_LENGTH(0);
+
+	hdr = NLMSG_PUT(skb, pid, seq, type, data_len);
+	hdr->nlmsg_flags = flags;
+	if(data_len > 0) {
+		data = NLMSG_DATA(hdr);
+		memcpy(data, buf, data_len);
+	}
+	status = netlink_unicast(ssk, skb, pid, MSG_DONTWAIT);
+	if(status == NLMSG_ALIGN(len)) {
+		status = len;
+	}
+	return(status);
+
+nlmsg_failure:
+	if(skb) {
+		kfree(skb);
+	}
+	IP_VS_DBG(2, "error creating netlink message\n");
+	return(status);
+}
+
+static int __ip_vs_user_sync_send_buf_to_peer(const void *buf, size_t len, 
+		__u32 type)
+{
+	__u32 peer_pid;
+	__u16 peer_flag;
+	__u16 peer_state;
+	int status;
+
+	spin_lock_bh(&ip_vs_user_sync_peer->lock);
+	IP_VS_USER_SYNC_PEER_GET(ip_vs_user_sync_peer, &peer_pid, &peer_flag, &peer_state);
+	spin_unlock_bh(&ip_vs_user_sync_peer->lock);
+	if(peer_state&IP_VS_USER_SYNC_TCP_S_TERMINATE) {
+		return(-EBUSY);
+	}
+	if(!(peer_state&IP_VS_USER_SYNC_TCP_S_ACTIVE)) {
+		return(-EBADF);
+	}
+
+	status = ip_vs_user_sync_send(ip_vs_user_sync, buf, NLMSG_LENGTH(len), type, 
+			IP_VS_USER_SYNC_SEND_FLAGS, 0, peer_pid);
+	if(status >= NLMSG_LENGTH(0)) {
+		return(status - NLMSG_LENGTH(0));
+	}
+
+	return(status);
+}
+
+
+int ip_vs_user_sync_send_buf_to_peer(const void *buf, size_t len, __u32 type)
+{
+	int i;
+	int delay;
+	int status = 0;
+	
+	for(i = 0, delay = HZ/10; i < IP_VS_USER_SYNC_RETRY ; i++, delay *= 2) {
+		status = __ip_vs_user_sync_send_buf_to_peer(buf, len, type);
+		if (status != -EFBIG) {
+			break;
+		}
+		IP_VS_DBG(2, "ip_vs_user_sync_send_buf_to_peer: retry %d\n", 
+				delay);
+                __set_current_state(TASK_INTERRUPTIBLE);
+                schedule_timeout(delay);
+	}
+
+	return(status);
+}
+
+
+/* ip_vs_user_sync_send_mesg_to_peer 
+ * wrapper for * ip_vs_user_sync_send_buf_to_peer that converts the data
+ * from a ip_vs_sync_mess + ip_vs_sync_conn 
+ * to * an ip_vs_user_sync_mesg + ip_vs_user_sync_conn 
+ *
+ * Note that the resulting buffer that is sent may be up to twice as
+ * large as the input buf. Also note that the resulting buffer
+ * must be less than IP_VS_USER_SYNC_PACKET_SIZE =~ 64k.
+ * However, as the nr_conn feild in struct ip_vs_sync_mesg is 8 bytes,
+ * the maximum resulting message size is:
+ * IP_VS_USER_SYNC_MESG_SIZE(256) =~ 12k which is well under the 64k limit
+ * */
+
+
+int ip_vs_user_sync_send_mesg_to_peer(const void *buf, size_t len, __u32 type) 
+{
+	struct ip_vs_sync_mesg *sync_mesg;
+	struct ip_vs_user_sync_mesg *nl_mesg;
+	struct ip_vs_sync_conn *sync_conn;
+	size_t nl_mesg_len;
+	size_t conn_len;
+	__u8 *nl_buf;
+	__u8 *nl_current;
+	const __u8 *sync_current;
+	size_t i;
+	int status = 0;
+
+	sync_mesg = (struct ip_vs_sync_mesg *)buf;
+	nl_mesg_len = IP_VS_USER_SYNC_MESG_SIZE(sync_mesg->nr_conns);
+	
+	nl_buf = kmalloc(nl_mesg_len, GFP_KERNEL);
+	if(!nl_buf) {
+		return -ENOMEM;
+	}
+	memset(nl_buf, 0, nl_mesg_len);
+
+	nl_mesg = (struct ip_vs_user_sync_mesg *)nl_buf;
+	nl_mesg->size =  nl_mesg_len;
+
+	nl_current = (__u8 *)nl_buf + sizeof(struct ip_vs_user_sync_mesg);
+	sync_current = (const __u8 *)buf + sizeof(struct ip_vs_sync_mesg);
+
+	for(i = 0 ; i < sync_mesg->nr_conns ; i++) {
+		sync_conn = (struct ip_vs_sync_conn *)sync_current;
+		if(ntohs(sync_conn->flags) & IP_VS_CONN_F_SEQ_MASK) {
+			conn_len = IP_VS_SYNC_FULL_CONN_SIZE;
+		}
+		else {
+			conn_len = IP_VS_SYNC_SIMPLE_CONN_SIZE;
+		}
+
+		memcpy(nl_current, sync_current, conn_len);
+		nl_current += sizeof(struct ip_vs_user_sync_conn);
+		sync_current += conn_len;
+	}
+
+	status = ip_vs_user_sync_send_buf_to_peer(nl_buf, nl_mesg_len, type);
+	if(status > 0) {
+		status = 0;
+	}
+
+	kfree(nl_buf);
+
+	return(status);
+}
+
+
+int ip_vs_user_sync_process_message(const void *buf, size_t len) {
+	struct ip_vs_sync_mesg *sync_mesg;
+	struct ip_vs_user_sync_mesg *nl_mesg;
+	struct ip_vs_sync_conn *sync_conn;
+	size_t nl_mesg_len;
+	size_t conn_len;
+	__u8 *sync_buf;
+	const __u8 *nl_current;
+	__u8 *sync_current;
+
+	nl_mesg = (struct ip_vs_user_sync_mesg *)buf;
+
+	sync_buf = kmalloc(len, GFP_KERNEL);
+	if(!sync_buf) {
+		return -ENOMEM;
+	}
+
+	nl_current = (const __u8 *)buf + sizeof(struct ip_vs_user_sync_mesg);
+	sync_current = (__u8 *)sync_buf + sizeof(struct ip_vs_sync_mesg);
+	sync_mesg = (struct ip_vs_sync_mesg *)sync_buf;
+	sync_mesg->size = sizeof(struct ip_vs_sync_mesg);
+	sync_mesg->nr_conns = 0;
+	sync_mesg->reserved = 0;
+
+	for(nl_mesg_len = sizeof(struct ip_vs_user_sync_mesg) ;
+			nl_mesg_len < nl_mesg->size ; 
+			nl_mesg_len += sizeof(struct ip_vs_user_sync_conn)) {
+		sync_conn = (struct ip_vs_sync_conn *)nl_current;
+		if(ntohs(sync_conn->flags) & IP_VS_CONN_F_SEQ_MASK) {
+			conn_len = IP_VS_SYNC_FULL_CONN_SIZE;
+		}
+		else {
+			conn_len = IP_VS_SYNC_SIMPLE_CONN_SIZE;
+		}
+
+		memcpy(sync_current, nl_current, conn_len);
+		nl_current += sizeof(struct ip_vs_user_sync_conn);
+		sync_current += conn_len;
+		sync_mesg->nr_conns++;
+		sync_mesg->size += conn_len;
+	}
+
+
+	ip_vs_process_message(sync_buf, sync_mesg->size);
+
+	kfree(sync_buf);
+
+	return(0);
+}
+
+
+static int ip_vs_user_sync_echo(struct sk_buff *skb) 
+{
+	struct nlmsghdr *hdr = (struct nlmsghdr *)skb->data;
+
+	return(ip_vs_user_sync_send(skb->sk, NLMSG_DATA(hdr), 
+				hdr->nlmsg_len - NLMSG_LENGTH(0),
+				hdr->nlmsg_type, hdr->nlmsg_flags,
+				hdr->nlmsg_seq, hdr->nlmsg_pid));
+}
+
+static int ip_vs_user_sync_close_pid(struct sk_buff *skb, __u32 pid) {
+	struct nlmsghdr *hdr;
+	struct nlmsghdr new_hdr;
+
+	hdr = (struct nlmsghdr *)skb->data;
+
+	return(ip_vs_user_sync_send(skb->sk, NLMSG_DATA(&new_hdr), 
+				NLMSG_LENGTH(0), 0, 
+				IP_VS_USER_SYNC_CLOSE_FLAGS, 0, pid));
+}
+
+static int ip_vs_user_sync_receive_skb(struct sk_buff *skb)
+{
+	int status = 0;
+	int no_err_ack = 0;
+	int control = 0;
+	__u32 peer_pid;
+	__u16 peer_flag;
+	__u16 peer_state;
+	struct nlmsghdr *hdr;
+	struct nlmsgerr *err;
+
+	hdr = (struct nlmsghdr *)skb->data;
+
+	spin_lock_bh(&ip_vs_user_sync_peer->lock);
+	IP_VS_USER_SYNC_PEER_GET(ip_vs_user_sync_peer, &peer_pid, &peer_flag, &peer_state);
+	if(peer_state&IP_VS_USER_SYNC_TCP_S_TERMINATE) {
+		status = -EBUSY;
+		no_err_ack = 1;
+		goto unlock;
+	}
+
+	switch(hdr->nlmsg_type) {
+		case 0: /* Regular, garden variety, message */
+		case NLMSG_DONE:
+			break;
+		case NLMSG_NOOP:
+			goto unlock;
+		case NLMSG_ERROR:
+			control = 1;
+			hdr->nlmsg_flags &= ~NLM_F_ACK;
+			err = NLMSG_DATA(hdr);
+			if(err->error) {
+				IP_VS_DBG(3, "Error! %d\n", err->error);
+			}
+			else {
+				IP_VS_DBG(3, "Ack!\n");
+			}
+			goto unlock;
+		case NLMSG_OVERRUN:
+			IP_VS_DBG(3, "Warning: Ignoring message type %d\n",
+					hdr->nlmsg_type);
+			status = -EINVAL;
+			no_err_ack = 1;
+			goto unlock;
+		default:
+			IP_VS_DBG(2, "Error: Bad type: %d\n",
+					hdr->nlmsg_type);
+			status = -EINVAL;
+			no_err_ack = 1;
+			goto unlock;
+	}
+
+	/* Check pid, seq and len */
+
+	if(!(hdr->nlmsg_flags&NLM_F_REQUEST) || hdr->nlmsg_flags&NLM_F_MULTI) {
+		IP_VS_DBG(2, "Error: !REQUEST || MULTI\n");
+		status = -EINVAL;
+		goto unlock;
+	}
+	if (hdr->nlmsg_flags & MSG_TRUNC) {
+		IP_VS_DBG(2, "Error: !TRUNC\n");
+		status = -ECOMM;
+		goto unlock;
+	}
+	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+		IP_VS_DBG(3, "Error: ADMIN\n");
+		status = -EPERM;
+		goto unlock;
+	}
+	if(hdr->nlmsg_flags&NLM_F_DUMP) {
+		status |= NLM_F_DUMP;
+		control = 1;
+	}
+
+	if(hdr->nlmsg_flags & IP_VS_USER_SYNC_TCP_F_OPEN) {
+		if(peer_state&IP_VS_USER_SYNC_TCP_S_ACTIVE) {
+			IP_VS_DBG(2, "Warning: netlink client pid "
+					"change %d->%d\n", peer_pid,
+					hdr->nlmsg_pid);
+			ip_vs_user_sync_close_pid(skb, peer_pid);
+		}
+		IP_VS_USER_SYNC_PEER_SET(ip_vs_user_sync_peer, hdr->nlmsg_pid,
+				hdr->nlmsg_flags, IP_VS_USER_SYNC_TCP_S_ACTIVE);
+		IP_VS_USER_SYNC_PEER_GET(ip_vs_user_sync_peer, &peer_pid, &peer_flag, 
+				&peer_state);
+		IP_VS_USER_SYNC_PEER_DUMP(2, ip_vs_user_sync_peer);
+	}
+
+unlock:
+	spin_unlock_bh(&ip_vs_user_sync_peer->lock);
+
+	if(peer_pid != hdr->nlmsg_pid) {
+		if (! hdr->nlmsg_flags & IP_VS_USER_SYNC_TCP_F_CLOSE) {
+			IP_VS_DBG(2, "Warning: non open or close message from "
+					"unkown pid: %u\n", hdr->nlmsg_pid);
+		}
+		IP_VS_USER_SYNC_HDR_DUMP(2, hdr);
+		ip_vs_user_sync_close_pid(skb, hdr->nlmsg_pid);
+		status = -EBUSY;
+		no_err_ack = 1;
+	}
+
+	if(status < 0 && !no_err_ack) {
+		netlink_ack(skb, hdr, status);
+		return(status);
+	}
+
+	if(hdr->nlmsg_flags&NLM_F_ACK) {
+		netlink_ack(skb, hdr, 0);
+	}
+	if(hdr->nlmsg_flags&NLM_F_ECHO) {
+		if((status = ip_vs_user_sync_echo(skb)) < 0) {
+			netlink_ack(skb, hdr, status);
+		}
+	}
+
+	if(hdr->nlmsg_flags & IP_VS_USER_SYNC_TCP_F_CLOSE &&
+			peer_pid == hdr->nlmsg_pid) {
+		IP_VS_USER_SYNC_PEER_RESET(ip_vs_user_sync_peer);
+		IP_VS_USER_SYNC_PEER_DUMP(2, ip_vs_user_sync_peer);
+	}
+	else if (!control && hdr->nlmsg_len != NLMSG_LENGTH(0)) {
+		ip_vs_user_sync_process_message(NLMSG_DATA(hdr), 
+				hdr->nlmsg_len - NLMSG_LENGTH(0));
+	}
+
+	return(status);
+}
+
+
+static void ip_vs_user_sync_receive(struct sock *sk, int len)
+{
+	int status;
+	struct sk_buff *skb;
+
+	do {
+		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+			status = ip_vs_user_sync_receive_skb(skb);
+			kfree_skb(skb);
+			if(status & NLM_F_DUMP) {
+				dump_sync_thread();
+			}
+		}
+	} while (ip_vs_user_sync && ip_vs_user_sync->receive_queue.qlen);
+}
+
+static void ip_vs_user_sync_sock_release(struct sock *s) {
+	if(s && s->socket) {
+		sock_release(s->socket);
+	}
+}
+
+
+int ip_vs_user_sync_send_mesg_wrapper(struct socket *sock, 
+		const char *buffer, const size_t length, void **data) 
+{
+	int status = 0;
+	
+	status = ip_vs_user_sync_send_mesg_to_peer(buffer, length, 0);
+
+	return((status == -EBADF || status == -EBUSY)?0:status);
+}
+
+
+int ip_vs_user_sync_done_wrapper(struct socket *sock, void **data) 
+{
+	int status = 0;
+
+	EnterFunction(2);
+	
+	status = ip_vs_user_sync_send_buf_to_peer(NULL, 0, NLMSG_DONE);
+
+	return((status == -EBADF || status == -EBUSY)?0:status);
+}
+
+
+struct socket *ip_vs_user_sync_open_wrapper(void **data) 
+{
+	/* Just return some rubbish */
+	return((struct socket *)~0);
+}
+
+/**********************************************************************
+ *
+ * Procfs
+ *
+ **********************************************************************/
+
+static int ip_vs_show_procfs(char *buffer, char **start, off_t offset,
+		int length)
+{
+	int len;
+
+	spin_lock_bh(&ip_vs_user_sync_peer->lock);
+	len = sprintf(buffer,
+			"Peer pid    %-6d\n"
+			"Peer state  0x%04x\n"
+			"Peer flag   0x%04x\n",
+			ip_vs_user_sync_peer->pid,
+			ip_vs_user_sync_peer->state,
+			ip_vs_user_sync_peer->flag);
+	spin_unlock_bh(&ip_vs_user_sync_peer->lock);
+
+	*start = buffer + offset;
+	len -= offset;
+	if(len > length) {
+		len = length;
+	}
+	if(len < 0) {
+		len = 0;
+	}
+
+	return(len);
+}
+
+/**********************************************************************
+ *
+ * Module stuff.
+ *
+ **********************************************************************/
+
+static int __init init(void)
+{
+	int status = 0;
+	struct proc_dir_entry *proc;
+
+	IP_VS_DBG(2, "Initialising netlink socket\n");
+	ip_vs_user_sync_peer = ip_vs_user_sync_peer_create(&status);
+	if(!ip_vs_user_sync_peer) {
+		return(status);
+	}
+
+	ip_vs_user_sync = netlink_kernel_create(NETLINK_IPVS, ip_vs_user_sync_receive);
+	if (!ip_vs_user_sync) 
+	{
+		printk(KERN_ERR "ip_vs_user_sync: initialisation failed: unable "
+			"to create kernel netlink socket\n");
+		ip_vs_user_sync_peer_destroy(ip_vs_user_sync_peer);
+		ip_vs_user_sync_peer = NULL;
+		return -ENOMEM;
+	}
+
+	proc = proc_net_create(IP_VS_USER_SYNC_PROC_FS_NAME, 0, ip_vs_show_procfs);
+	if(!proc) {
+		ip_vs_user_sync_peer_destroy(ip_vs_user_sync_peer);
+		ip_vs_user_sync_peer = NULL;
+		ip_vs_user_sync_sock_release(ip_vs_user_sync);
+		ip_vs_user_sync = NULL;
+		return -ENOMEM;
+	}
+
+	proc->owner = THIS_MODULE;
+
+	ip_vs_sync_table_register(ip_vs_user_sync_send_mesg_wrapper,
+			NULL, ip_vs_user_sync_open_wrapper,
+			ip_vs_user_sync_open_wrapper, NULL, NULL, 
+			ip_vs_user_sync_done_wrapper, NULL);
+	start_sync_thread(IP_VS_STATE_MASTER, NULL);
+
+	register_netdevice_notifier(&ip_vs_user_sync_notifier);
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	IP_VS_DBG(2, "Uninitialising netlink socket\n");
+	stop_sync_thread();
+	ip_vs_sync_table_register_default();
+	unregister_netdevice_notifier(&ip_vs_user_sync_notifier);
+	proc_net_remove(IP_VS_USER_SYNC_PROC_FS_NAME);
+	ip_vs_user_sync_sock_release(ip_vs_user_sync);
+	ip_vs_user_sync = NULL;
+	ip_vs_user_sync_peer_destroy(ip_vs_user_sync_peer);
+	ip_vs_user_sync_peer = NULL;
+}
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Netlink socket for IPVS");
+
+module_init(init);
+module_exit(fini);
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//net/ipv4/ipvs/ip_vs_user_sync.h linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_user_sync.h
--- linux-2.4.26//net/ipv4/ipvs/ip_vs_user_sync.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26.user_sync//net/ipv4/ipvs/ip_vs_user_sync.h	2004-04-20 13:46:47.000000000 +0900
@@ -0,0 +1,60 @@
+/**********************************************************************
+ * ip_vs_user_sync.h                                       September 2002
+ * Horms                                             horms@verge.net.au
+ *
+ * ip_vs_user_sync
+ * Netlink socket to communicate with LVS
+ * Copyright (C) 2002  Horms
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307  USA
+ **********************************************************************/
+
+#ifndef __IP_VS_USER_SYNC_H
+#define __IP_VS_USER_SYNC_H
+
+#define IP_VS_USER_SYNC_TCP_F_OPEN     0x1000
+#define IP_VS_USER_SYNC_TCP_F_CLOSE    0x2000
+
+#define IP_VS_USER_SYNC_SEND_FLAGS   NLM_F_REQUEST
+#define IP_VS_USER_SYNC_DUMP_FLAGS   IP_VS_USER_SYNC_SEND_FLAGS|NLM_F_DUMP
+
+#define IP_VS_USER_SYNC_CLOSE_FLAGS  \
+	IP_VS_USER_SYNC_TCP_F_CLOSE|NLM_F_REQUEST|IP_VS_USER_SYNC_SEND_FLAGS
+#define IP_VS_USER_SYNC_OPEN_FLAGS   \
+	IP_VS_USER_SYNC_TCP_F_OPEN|NLM_F_REQUEST|IP_VS_USER_SYNC_SEND_FLAGS
+
+#define IP_VS_USER_SYNC_TCP_S_ACTIVE    0x00001
+#define IP_VS_USER_SYNC_TCP_S_TERMINATE 0x00002
+
+#define IP_VS_USER_SYNC_PROC_FS_NAME "ip_vs_user_sync"
+
+/* 64k less a bit for internal stuff */
+#define IP_VS_USER_SYNC_PACKET_SIZE (65536 - 36) 
+
+
+struct ip_vs_user_sync_conn {
+	__u8 pad[48];
+};
+
+struct ip_vs_user_sync_mesg {
+	__u16 size;
+};
+
+#define IP_VS_USER_SYNC_MESG_SIZE(_nr_conn) \
+	( sizeof(struct ip_vs_user_sync_mesg) + \
+	(_nr_conn) * sizeof(struct ip_vs_user_sync_conn) )
+
+#endif /* __IP_VS_USER_SYNC_H */
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//Documentation/Configure.help linux-2.4.26.user_sync//Documentation/Configure.help
--- linux-2.4.26//Documentation/Configure.help	2004-04-20 13:44:46.000000000 +0900
+++ linux-2.4.26.user_sync//Documentation/Configure.help	2004-04-20 13:46:47.000000000 +0900
@@ -3549,6 +3549,24 @@
   it as a module, say M here and read Documentation/modules.txt. If
   unsure, say N.
 
+IPVS: User-Space Connection Synchronisation
+CONFIG_IP_VS_USER_SYNC
+  Allows synchronisation of the LVS connection table to
+  be passed to a user-space daemon via a netlink socket.
+  This is in contrast to the default behaviour of LVS 
+  connection synchronisation which is done using kernel 
+  daemons that communicate using multicast UDP.
+
+  It is recommended that this be compiled as a module
+  which is inserted if this behaviour is desired. Else
+  the default synchronisation behaviour will be available.
+
+  For more information see http://www.ultramonkey.org/papers/
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
 AH/ESP match support (EXPERIMENTAL)
 CONFIG_IP6_NF_MATCH_AHESP
   This module allows one to match AH and ESP packets.
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//include/net/ip_vs.h linux-2.4.26.user_sync//include/net/ip_vs.h
--- linux-2.4.26//include/net/ip_vs.h	2004-04-14 22:05:40.000000000 +0900
+++ linux-2.4.26.user_sync//include/net/ip_vs.h	2004-04-20 13:46:47.000000000 +0900
@@ -218,6 +218,131 @@
 };
 
 
+/*
+ *     IPVS connection entry hash table
+ */
+
+#define VS_STATE_INPUT	        0
+#define VS_STATE_OUTPUT	        4
+#define VS_STATE_INPUT_ONLY	8
+
+/*
+ *	Delta sequence info structure
+ *	Each ip_vs_conn has 2 (output AND input seq. changes).
+ *      Only used in the VS/NAT.
+ */
+struct ip_vs_seq {
+	__u32           init_seq;       /* Add delta from this seq */
+	__u32           delta;          /* Delta in sequence numbers */
+	__u32           previous_delta; /* Delta in sequence numbers
+					   before last resized pkt */
+};
+
+
+/*
+ *	IPVS sync connection entry
+ */
+struct ip_vs_sync_conn {
+	__u8			reserved;
+
+	/* Protocol, addresses and port numbers */
+	__u8			protocol;       /* Which protocol (TCP/UDP) */
+	__u16			cport;
+	__u16                   vport;
+	__u16                   dport;
+	__u32                   caddr;          /* client address */
+	__u32                   vaddr;          /* virtual address */
+	__u32                   daddr;          /* destination address */
+
+	/* Flags and state transition */
+	__u16                   flags;          /* status flags */
+	__u16                   state;          /* state info */
+
+	/* The sequence options start here */
+};
+
+struct ip_vs_sync_conn_options {
+	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
+	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
+};
+
+#define IP_VS_SYNC_CONN_TIMEOUT (3*60*HZ)
+#define IP_VS_SYNC_SIMPLE_CONN_SIZE  (sizeof(struct ip_vs_sync_conn))
+#define IP_VS_SYNC_FULL_CONN_SIZE  \
+(sizeof(struct ip_vs_sync_conn) + sizeof(struct ip_vs_sync_conn_options))
+
+
+/*
+  The master mulitcasts messages to the backup load balancers in the
+  following format.
+
+       0                   1                   2                   3
+       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |  Count Conns  |   Reserved    |            Size               |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (1)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                            .                                  |
+      |                            .                                  |
+      |                            .                                  |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (n)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+struct ip_vs_sync_mesg {
+	__u8                    nr_conns;
+	__u8                    reserved;
+	__u16                   size;
+
+	/* ip_vs_sync_conn entries start here */
+};
+
+
+/* Trailing  sizeof(struct ip_vs_sync_conn_options) is to allow 
+ * the full connection count to be used by allowing a bit of extra
+ * space, just in case the last connection is FULL_CONN_SIZE
+ * instead of SIMPLE_CONN_SIZE */
+
+/* At the very least the message needs to hold one message */
+#define IP_VS_SYNC_MESG_MAX_SIZE_MIN \
+	(IP_VS_SYNC_SIMPLE_CONN_SIZE + sizeof(struct ip_vs_sync_mesg) \
+	 + sizeof(struct ip_vs_sync_conn_options))
+
+/* At most, 256 messages can be carried. This is because
+ * the nr_conns element in the ip_vs_sync_mesg structure
+ * is an unsigned 8bit integer, and thus has a valid range
+ * of 0 - 255. Beyond that a wraparound will occur. */
+#define IP_VS_SYNC_MESG_MAX_SIZE_MAX \
+	(255 * IP_VS_SYNC_SIMPLE_CONN_SIZE + sizeof(struct ip_vs_sync_mesg) \
+	 + sizeof(struct ip_vs_sync_conn_options))
+
+/* By default, send 50 connections per message. This fits niceley
+ * into a 1500 MTU packet */
+#define IP_VS_SYNC_MESG_MAX_SIZE_DEFAULT \
+	(50 * IP_VS_SYNC_SIMPLE_CONN_SIZE + sizeof(struct ip_vs_sync_mesg) \
+	 + sizeof(struct ip_vs_sync_conn_options))
+
+#define IP_VS_SYNC_MESG_MAX_SIZE \
+	((sysctl_ip_vs_sync_msg_max_size > IP_VS_SYNC_MESG_MAX_SIZE_MAX) ? \
+	IP_VS_SYNC_MESG_MAX_SIZE_MAX: \
+	((sysctl_ip_vs_sync_msg_max_size < IP_VS_SYNC_MESG_MAX_SIZE_MIN) ? \
+	 IP_VS_SYNC_MESG_MAX_SIZE_MIN : sysctl_ip_vs_sync_msg_max_size))
+
+
+#define IP_VS_SYNC_FREQUENCY_DEFAULT 50
+#define IP_VS_SYNC_FREQUENCY \
+	((sysctl_ip_vs_sync_frequency < 1) ? 1 : sysctl_ip_vs_sync_frequency)
+
+#define IP_VS_SYNC_THRESHOLD_DEFAULT 3     
+#define IP_VS_SYNC_THRESHOLD \
+	((sysctl_ip_vs_sync_threshold < 0) ? 0 : \
+	 (sysctl_ip_vs_sync_threshold >= IP_VS_SYNC_FREQUENCY) ? \
+	 IP_VS_SYNC_FREQUENCY - 1 : sysctl_ip_vs_sync_threshold) 
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>
@@ -316,7 +441,9 @@
 	NET_IPV4_VS_CACHE_BYPASS=22,
 	NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
 	NET_IPV4_VS_SYNC_THRESHOLD=24,
-	NET_IPV4_VS_NAT_ICMP_SEND=25,
+	NET_IPV4_VS_SYNC_FREQUENCY=25,
+	NET_IPV4_VS_SYNC_MSG_MAX_SIZE=26,
+	NET_IPV4_VS_NAT_ICMP_SEND=27,
 	NET_IPV4_VS_LAST
 };
 
@@ -362,19 +489,6 @@
 
 
 /*
- *	Delta sequence info structure
- *	Each ip_vs_conn has 2 (output AND input seq. changes).
- *      Only used in the VS/NAT.
- */
-struct ip_vs_seq {
-	__u32           init_seq;       /* Add delta from this seq */
-	__u32           delta;          /* Delta in sequence numbers */
-	__u32           previous_delta; /* Delta in sequence numbers
-					   before last resized pkt */
-};
-
-
-/*
  *	IPVS statistics object
  */
 struct ip_vs_stats
@@ -508,7 +622,7 @@
 	struct list_head        n_list;   /* d-linked list head */
 	char			*name;    /* scheduler name */
 	atomic_t                refcnt;   /* reference counter */
-	struct module		*module;  /* THIS_MODULE/NULL */
+	struct module           *module;  /* THIS_MODULE/NULL */
 
 	/* scheduler initializing service */
 	int (*init_service)(struct ip_vs_service *svc);
@@ -561,9 +675,6 @@
  *     (from ip_vs_conn.c)
  */
 
-/*
- *     IPVS connection entry hash table
- */
 #ifndef CONFIG_IP_VS_TAB_BITS
 #define CONFIG_IP_VS_TAB_BITS   12
 #endif
@@ -580,6 +691,10 @@
 #define IP_VS_CONN_TAB_SIZE     (1 << IP_VS_CONN_TAB_BITS)
 #define IP_VS_CONN_TAB_MASK     (IP_VS_CONN_TAB_SIZE - 1)
 
+/*
+ *     IPVS connection entry hash table
+ */
+
 #define VS_STATE_INPUT	        0
 #define VS_STATE_OUTPUT	        4
 #define VS_STATE_INPUT_ONLY	8
@@ -701,6 +816,8 @@
 extern int sysctl_ip_vs_cache_bypass;
 extern int sysctl_ip_vs_expire_nodest_conn;
 extern int sysctl_ip_vs_sync_threshold;
+extern int sysctl_ip_vs_sync_frequency;
+extern int sysctl_ip_vs_sync_msg_max_size;
 extern int sysctl_ip_vs_nat_icmp_send;
 extern struct ip_vs_stats ip_vs_stats;
 
@@ -727,7 +844,9 @@
 extern char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
 extern int start_sync_thread(int state, char *mcast_ifn);
 extern int stop_sync_thread(void);
+extern int dump_sync_thread(void);
 extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
+extern void ip_vs_process_message(const char *buffer, const size_t buflen);
 
 
 /*
@@ -927,6 +1046,43 @@
 	return 0;
 }
 
+typedef int ip_vs_sync_table_send_mesg_handler_t(struct socket *sock,
+		const char *buffer, const size_t length, void **data);
+typedef int ip_vs_sync_table_recv_loop_handler_t(struct socket *sock,
+		void **data);
+typedef struct sk_buff *ip_vs_sync_table_recv_ready_handler_t(
+		struct socket *sock, void **data);
+typedef struct socket *ip_vs_sync_table_open_handler_t(void **data);
+typedef int ip_vs_sync_table_close_handler_t(struct socket *sock, void **data);
+typedef int ip_vs_sync_table_done_handler_t(struct socket *sock, void **data);
+
+typedef struct {
+	ip_vs_sync_table_send_mesg_handler_t  *send_mesg;
+	ip_vs_sync_table_recv_loop_handler_t  *recv_loop;
+	ip_vs_sync_table_open_handler_t       *open_send;
+	ip_vs_sync_table_open_handler_t       *open_recv;
+	ip_vs_sync_table_close_handler_t      *close_send;
+	ip_vs_sync_table_close_handler_t      *close_recv;
+	ip_vs_sync_table_done_handler_t       *done;
+	void *data;
+	int state;
+	spinlock_t lock;
+} ip_vs_sync_table_t;
+
+int __init ip_vs_sync_init(void);
+int __exit ip_vs_sync_cleanup(void);
+int ip_vs_sync_table_register(ip_vs_sync_table_send_mesg_handler_t *send_mesg,
+		ip_vs_sync_table_recv_loop_handler_t *recv_loop,
+		ip_vs_sync_table_open_handler_t *open_send,
+		ip_vs_sync_table_open_handler_t *open_recv,
+		ip_vs_sync_table_close_handler_t *close_send,
+		ip_vs_sync_table_close_handler_t *close_recv,
+		ip_vs_sync_table_done_handler_t *done,
+		void *data);
+
+void ip_vs_sync_table_register_default(void);
+
+void ip_vs_conn_dump_to_sync(void);
 #endif /* __KERNEL__ */
 
 #endif	/* _IP_VS_H */
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//include/net/ip_vs_user_sync.h linux-2.4.26.user_sync//include/net/ip_vs_user_sync.h
--- linux-2.4.26//include/net/ip_vs_user_sync.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26.user_sync//include/net/ip_vs_user_sync.h	2004-04-20 13:46:47.000000000 +0900
@@ -0,0 +1,60 @@
+/**********************************************************************
+ * ip_vs_user_sync.h                                       September 2002
+ * Horms                                             horms@verge.net.au
+ *
+ * ip_vs_user_sync
+ * Netlink socket to communicate with LVS
+ * Copyright (C) 2002  Horms
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307  USA
+ **********************************************************************/
+
+#ifndef __IP_VS_USER_SYNC_H
+#define __IP_VS_USER_SYNC_H
+
+#define IP_VS_USER_SYNC_TCP_F_OPEN     0x1000
+#define IP_VS_USER_SYNC_TCP_F_CLOSE    0x2000
+
+#define IP_VS_USER_SYNC_SEND_FLAGS   NLM_F_REQUEST
+#define IP_VS_USER_SYNC_DUMP_FLAGS   IP_VS_USER_SYNC_SEND_FLAGS|NLM_F_DUMP
+
+#define IP_VS_USER_SYNC_CLOSE_FLAGS  \
+	IP_VS_USER_SYNC_TCP_F_CLOSE|NLM_F_REQUEST|IP_VS_USER_SYNC_SEND_FLAGS
+#define IP_VS_USER_SYNC_OPEN_FLAGS   \
+	IP_VS_USER_SYNC_TCP_F_OPEN|NLM_F_REQUEST|IP_VS_USER_SYNC_SEND_FLAGS
+
+#define IP_VS_USER_SYNC_TCP_S_ACTIVE    0x00001
+#define IP_VS_USER_SYNC_TCP_S_TERMINATE 0x00002
+
+#define IP_VS_USER_SYNC_PROC_FS_NAME "ip_vs_user_sync"
+
+/* 64k less a bit for internal stuff */
+#define IP_VS_USER_SYNC_PACKET_SIZE (65536 - 36) 
+
+
+struct ip_vs_user_sync_conn {
+	__u8 pad[48];
+};
+
+struct ip_vs_user_sync_mesg {
+	__u16 size;
+};
+
+#define IP_VS_USER_SYNC_MESG_SIZE(_nr_conn) \
+	( sizeof(struct ip_vs_user_sync_mesg) + \
+	(_nr_conn) * sizeof(struct ip_vs_user_sync_conn) )
+
+#endif /* __IP_VS_USER_SYNC_H */
diff -ruN -x '*.o' -x '*.rej' -x '*.orig' -x .depend -x '*.flags' -x compile.h linux-2.4.26//include/linux/netlink.h linux-2.4.26.user_sync//include/linux/netlink.h
--- linux-2.4.26//include/linux/netlink.h	2002-11-29 08:53:15.000000000 +0900
+++ linux-2.4.26.user_sync//include/linux/netlink.h	2004-04-20 13:46:47.000000000 +0900
@@ -11,6 +11,7 @@
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
+#define NETLINK_IPVS		15	/* IPVS hook */
 #define NETLINK_TAPBASE		16	/* 16 to 31 are ethertap */
 
 #define MAX_LINKS 32		
