* 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>
/* 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 */
+ __be16 cport;
+ __be16 vport;
+ __be16 dport;
+ __be32 caddr; /* client address */
+ __be32 vaddr; /* virtual address */
+ __be32 daddr; /* destination address */
/* Flags and state transition */
- __u16 flags; /* status flags */
- __u16 state; /* state info */
+ __be16 flags; /* status flags */
+ __be16 state; /* state info */
/* The sequence options start here */
};
/* 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;
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;
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;
} 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;
*/
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);
*/
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);
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;
static int bind_mcastif_addr(struct socket *sock, char *ifname)
{
struct net_device *dev;
- u32 addr;
+ __be32 addr;
struct sockaddr_in sin;
if ((dev = __dev_get_by_name(ifname)) == NULL)
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;
{
struct socket *sock;
struct ip_vs_sync_buff *sb;
- struct ip_vs_sync_mesg *m;
/* create the sending multicast socket */
sock = make_send_sock();
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);
+ msleep_interruptible(1000);
}
/* clean up the sync_buff queue */
if (stop_backup_sync)
break;
- __set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
+ msleep_interruptible(1000);
}
/* release the sending multicast socket */
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);
+ msleep_interruptible(1000);
goto repeat;
}
int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
{
- DECLARE_COMPLETION(startup);
+ DECLARE_COMPLETION_ONSTACK(startup);
pid_t pid;
if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
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;
}
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);
+ msleep_interruptible(1000);
goto repeat;
}
IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
IP_VS_INFO("stopping sync thread %d ...\n",
- (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
+ (state == IP_VS_STATE_MASTER) ?
+ sync_master_pid : sync_backup_pid);
__set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&stop_sync_wait, &wait);