Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / ipv4 / ipvs / ip_vs_sync.c
index 7b727a9..1bca714 100644 (file)
  *     Alexandre Cassen        :       Added master & backup support at a time.
  *     Alexandre Cassen        :       Added SyncID support for incoming sync
  *                                     messages filtering.
+ *     Justin Ossevoort        :       Fix endian problem on sync message size.
  */
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/inetdevice.h>
 #include <linux/net.h>
 #include <linux/completion.h>
-
+#include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/igmp.h>                 /* for ip_mc_join_group */
+#include <linux/udp.h>
 
 #include <net/ip.h>
 #include <net/sock.h>
@@ -118,11 +121,11 @@ struct ip_vs_sync_buff {
 
 /* the sync_buff list head and the lock */
 static LIST_HEAD(ip_vs_sync_queue);
-static spinlock_t ip_vs_sync_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ip_vs_sync_lock);
 
 /* current sync_buff for accepting new conn entries */
 static struct ip_vs_sync_buff   *curr_sb = NULL;
-static spinlock_t curr_sb_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(curr_sb_lock);
 
 /* ipvs sync daemon state */
 volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
@@ -279,6 +282,9 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
        char *p;
        int i;
 
+       /* Convert size back to host byte order */
+       m->size = ntohs(m->size);
+
        if (buflen != m->size) {
                IP_VS_ERR("bogus message\n");
                return;
@@ -293,16 +299,24 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 
        p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
        for (i=0; i<m->nr_conns; i++) {
+               unsigned flags;
+
                s = (struct ip_vs_sync_conn *)p;
-               cp = ip_vs_conn_in_get(s->protocol,
-                                      s->caddr, s->cport,
-                                      s->vaddr, s->vport);
+               flags = ntohs(s->flags);
+               if (!(flags & IP_VS_CONN_F_TEMPLATE))
+                       cp = ip_vs_conn_in_get(s->protocol,
+                                              s->caddr, s->cport,
+                                              s->vaddr, s->vport);
+               else
+                       cp = ip_vs_ct_in_get(s->protocol,
+                                              s->caddr, s->cport,
+                                              s->vaddr, s->vport);
                if (!cp) {
                        cp = ip_vs_conn_new(s->protocol,
                                            s->caddr, s->cport,
                                            s->vaddr, s->vport,
                                            s->daddr, s->dport,
-                                           ntohs(s->flags), NULL);
+                                           flags, NULL);
                        if (!cp) {
                                IP_VS_ERR("ip_vs_conn_new failed\n");
                                return;
@@ -311,11 +325,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
                } else if (!cp->dest) {
                        /* it is an entry created by the synchronization */
                        cp->state = ntohs(s->state);
-                       cp->flags = ntohs(s->flags) | IP_VS_CONN_F_HASHED;
+                       cp->flags = flags | IP_VS_CONN_F_HASHED;
                }       /* Note that we don't touch its state and flags
                           if it is a normal entry. */
 
-               if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) {
+               if (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;
@@ -339,7 +353,7 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
  */
 static void set_mcast_loop(struct sock *sk, u_char loop)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
 
        /* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
        lock_sock(sk);
@@ -352,7 +366,7 @@ static void set_mcast_loop(struct sock *sk, u_char loop)
  */
 static void set_mcast_ttl(struct sock *sk, u_char ttl)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
 
        /* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
        lock_sock(sk);
@@ -366,7 +380,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl)
 static int set_mcast_if(struct sock *sk, char *ifname)
 {
        struct net_device *dev;
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
 
        if ((dev = __dev_get_by_name(ifname)) == NULL)
                return -ENODEV;
@@ -555,55 +569,48 @@ static struct socket * make_receive_sock(void)
 static int
 ip_vs_send_async(struct socket *sock, const char *buffer, const size_t length)
 {
-       struct msghdr   msg;
-       mm_segment_t    oldfs;
-       struct iovec    iov;
+       struct msghdr   msg = {.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL};
+       struct kvec     iov;
        int             len;
 
        EnterFunction(7);
        iov.iov_base     = (void *)buffer;
        iov.iov_len      = length;
-       msg.msg_name     = 0;
-       msg.msg_namelen  = 0;
-       msg.msg_iov      = &iov;
-       msg.msg_iovlen   = 1;
-       msg.msg_control  = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_flags    = MSG_DONTWAIT|MSG_NOSIGNAL;
-
-       oldfs = get_fs(); set_fs(KERNEL_DS);
-       len = sock_sendmsg(sock, &msg, (size_t)(length));
-       set_fs(oldfs);
+
+       len = kernel_sendmsg(sock, &msg, &iov, 1, (size_t)(length));
 
        LeaveFunction(7);
        return len;
 }
 
+static void
+ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg)
+{
+       int msize;
+
+       msize = msg->size;
+
+       /* Put size in network byte order */
+       msg->size = htons(msg->size);
+
+       if (ip_vs_send_async(sock, (char *)msg, msize) != msize)
+               IP_VS_ERR("ip_vs_send_async error\n");
+}
 
 static int
 ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
 {
-       struct msghdr           msg;
-       struct iovec            iov;
+       struct msghdr           msg = {NULL,};
+       struct kvec             iov;
        int                     len;
-       mm_segment_t            oldfs;
 
        EnterFunction(7);
 
        /* Receive a packet */
        iov.iov_base     = buffer;
        iov.iov_len      = (size_t)buflen;
-       msg.msg_name     = 0;
-       msg.msg_namelen  = 0;
-       msg.msg_iov      = &iov;
-       msg.msg_iovlen   = 1;
-       msg.msg_control  = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_flags    = 0;
-
-       oldfs = get_fs(); set_fs(KERNEL_DS);
-       len = sock_recvmsg(sock, &msg, buflen, 0);
-       set_fs(oldfs);
+
+       len = kernel_recvmsg(sock, &msg, &iov, 1, buflen, 0);
 
        if (len < 0)
                return -1;
@@ -625,7 +632,6 @@ static void sync_master_loop(void)
 {
        struct socket *sock;
        struct ip_vs_sync_buff *sb;
-       struct ip_vs_sync_mesg *m;
 
        /* create the sending multicast socket */
        sock = make_send_sock();
@@ -638,27 +644,20 @@ static void sync_master_loop(void)
 
        for (;;) {
                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");
+                       ip_vs_send_sync_msg(sock, sb->mesg);
                        ip_vs_sync_buff_release(sb);
                }
 
                /* check if entries stay in curr_sb for 2 seconds */
                if ((sb = get_curr_sync_buff(2*HZ))) {
-                       m = sb->mesg;
-                       if (ip_vs_send_async(sock, (char *)m,
-                                            m->size) != m->size)
-                               IP_VS_ERR("ip_vs_send_async error\n");
+                       ip_vs_send_sync_msg(sock, sb->mesg);
                        ip_vs_sync_buff_release(sb);
                }
 
                if (stop_master_sync)
                        break;
 
-               __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
+               ssleep(1);
        }
 
        /* clean up the sync_buff queue */
@@ -715,8 +714,7 @@ static void sync_backup_loop(void)
                if (stop_backup_sync)
                        break;
 
-               __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
+               ssleep(1);
        }
 
        /* release the sending multicast socket */
@@ -828,8 +826,7 @@ static int fork_sync_thread(void *startup)
        if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) {
                IP_VS_ERR("could not create sync_thread due to %d... "
                          "retrying.\n", pid);
-               current->state = TASK_UNINTERRUPTIBLE;
-               schedule_timeout(HZ);
+               ssleep(1);
                goto repeat;
        }
 
@@ -852,10 +849,10 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 
        ip_vs_sync_state |= state;
        if (state == IP_VS_STATE_MASTER) {
-               strcpy(ip_vs_master_mcast_ifn, mcast_ifn);
+               strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, sizeof(ip_vs_master_mcast_ifn));
                ip_vs_master_syncid = syncid;
        } else {
-               strcpy(ip_vs_backup_mcast_ifn, mcast_ifn);
+               strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, sizeof(ip_vs_backup_mcast_ifn));
                ip_vs_backup_syncid = syncid;
        }
 
@@ -863,8 +860,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
        if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
                IP_VS_ERR("could not create fork_sync_thread due to %d... "
                          "retrying.\n", pid);
-               current->state = TASK_UNINTERRUPTIBLE;
-               schedule_timeout(HZ);
+               ssleep(1);
                goto repeat;
        }