⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_vs_sync.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * IPVS         An implementation of the IP virtual server support for the *              LINUX operating system.  IPVS is now implemented as a module *              over the NetFilter framework. IPVS can be used to build a *              high-performance and highly available server based on a *              cluster of servers. * * Version:     $Id: ip_vs_sync.c,v 1.13 2003/06/08 09:31:19 wensong Exp $ * * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org> * * ip_vs_sync:  sync connection info from master load balancer to backups *              through multicast * * Changes: *	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/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 <net/ip.h>#include <net/sock.h>#include <asm/uaccess.h>                /* for get_fs and set_fs */#include <net/ip_vs.h>#define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */#define IP_VS_SYNC_PORT  8848          /* multicast port *//* *	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  |    SyncID     |            Size               |      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      |                                                               |      |                    IPVS Sync Connection (1)                   |      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      |                            .                                  |      |                            .                                  |      |                            .                                  |      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      |                                                               |      |                    IPVS Sync Connection (n)                   |      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/#define SYNC_MESG_HEADER_LEN	4struct ip_vs_sync_mesg {	__u8                    nr_conns;	__u8                    syncid;	__u16                   size;	/* ip_vs_sync_conn entries start here */};/* the maximum length of sync (sending/receiving) message */static int sync_send_mesg_maxlen;static int sync_recv_mesg_maxlen;struct ip_vs_sync_buff {	struct list_head        list;	unsigned long           firstuse;	/* pointers for the message data */	struct ip_vs_sync_mesg  *mesg;	unsigned char           *head;	unsigned char           *end;};/* the sync_buff list head and the lock */static LIST_HEAD(ip_vs_sync_queue);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 DEFINE_SPINLOCK(curr_sb_lock);/* ipvs sync daemon state */volatile int ip_vs_sync_state = IP_VS_STATE_NONE;volatile int ip_vs_master_syncid = 0;volatile int ip_vs_backup_syncid = 0;/* multicast interface name */char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN];char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];/* multicast addr */static struct sockaddr_in mcast_addr;static inline void sb_queue_tail(struct ip_vs_sync_buff *sb){	spin_lock(&ip_vs_sync_lock);	list_add_tail(&sb->list, &ip_vs_sync_queue);	spin_unlock(&ip_vs_sync_lock);}static inline struct ip_vs_sync_buff * sb_dequeue(void){	struct ip_vs_sync_buff *sb;	spin_lock_bh(&ip_vs_sync_lock);	if (list_empty(&ip_vs_sync_queue)) {		sb = NULL;	} else {		sb = list_entry(ip_vs_sync_queue.next,				struct ip_vs_sync_buff,				list);		list_del(&sb->list);	}	spin_unlock_bh(&ip_vs_sync_lock);	return sb;}static inline struct ip_vs_sync_buff * ip_vs_sync_buff_create(void){	struct ip_vs_sync_buff *sb;	if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC)))		return NULL;	if (!(sb->mesg=kmalloc(sync_send_mesg_maxlen, GFP_ATOMIC))) {		kfree(sb);		return NULL;	}	sb->mesg->nr_conns = 0;	sb->mesg->syncid = ip_vs_master_syncid;	sb->mesg->size = 4;	sb->head = (unsigned char *)sb->mesg + 4;	sb->end = (unsigned char *)sb->mesg + sync_send_mesg_maxlen;	sb->firstuse = jiffies;	return sb;}static inline void ip_vs_sync_buff_release(struct ip_vs_sync_buff *sb){	kfree(sb->mesg);	kfree(sb);}/* *	Get the current sync buffer if it has been created for more *	than the specified time or the specified time is zero. */static inline struct ip_vs_sync_buff *get_curr_sync_buff(unsigned long time){	struct ip_vs_sync_buff *sb;	spin_lock_bh(&curr_sb_lock);	if (curr_sb && (time == 0 ||			time_before(jiffies - curr_sb->firstuse, time))) {		sb = curr_sb;		curr_sb = NULL;	} else		sb = NULL;	spin_unlock_bh(&curr_sb_lock);	return sb;}/* *      Add an ip_vs_conn information into the current sync_buff. *      Called by ip_vs_in. */void ip_vs_sync_conn(struct ip_vs_conn *cp){	struct ip_vs_sync_mesg *m;	struct ip_vs_sync_conn *s;	int len;	spin_lock(&curr_sb_lock);	if (!curr_sb) {		if (!(curr_sb=ip_vs_sync_buff_create())) {			spin_unlock(&curr_sb_lock);			IP_VS_ERR("ip_vs_sync_buff_create failed.\n");			return;		}	}	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :		SIMPLE_CONN_SIZE;	m = curr_sb->mesg;	s = (struct ip_vs_sync_conn *)curr_sb->head;	/* copy members */	s->protocol = cp->protocol;	s->cport = cp->cport;	s->vport = cp->vport;	s->dport = cp->dport;	s->caddr = cp->caddr;	s->vaddr = cp->vaddr;	s->daddr = cp->daddr;	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);	s->state = htons(cp->state);	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {		struct ip_vs_sync_conn_options *opt =			(struct ip_vs_sync_conn_options *)&s[1];		memcpy(opt, &cp->in_seq, sizeof(*opt));	}	m->nr_conns++;	m->size += len;	curr_sb->head += len;	/* check if there is a space for next one */	if (curr_sb->head+FULL_CONN_SIZE > curr_sb->end) {		sb_queue_tail(curr_sb);		curr_sb = NULL;	}	spin_unlock(&curr_sb_lock);	/* synchronize its controller if it has */	if (cp->control)		ip_vs_sync_conn(cp->control);}/* *      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){	struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;	struct ip_vs_sync_conn *s;	struct ip_vs_sync_conn_options *opt;	struct ip_vs_conn *cp;	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;	}	/* SyncID sanity check */	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {		IP_VS_DBG(7, "Ignoring incoming msg with syncid = %d\n",			  m->syncid);		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;		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,					    flags, NULL);			if (!cp) {				IP_VS_ERR("ip_vs_conn_new failed\n");				return;			}			cp->state = ntohs(s->state);		} else if (!cp->dest) {			/* it is an entry created by the synchronization */			cp->state = ntohs(s->state);			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 (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;		} else			p += SIMPLE_CONN_SIZE;		atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);		cp->timeout = IP_VS_SYNC_CONN_TIMEOUT;		ip_vs_conn_put(cp);		if (p > buffer+buflen) {			IP_VS_ERR("bogus message\n");			return;		}	}}/* *      Setup loopback of outgoing multicasts on a sending socket */static void set_mcast_loop(struct sock *sk, u_char loop){	struct inet_sock *inet = inet_sk(sk);	/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */	lock_sock(sk);	inet->mc_loop = loop ? 1 : 0;	release_sock(sk);}/* *      Specify TTL for outgoing multicasts on a sending socket */static void set_mcast_ttl(struct sock *sk, u_char ttl){	struct inet_sock *inet = inet_sk(sk);	/* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */	lock_sock(sk);	inet->mc_ttl = ttl;	release_sock(sk);}/* *      Specifiy default interface for outgoing multicasts */static int set_mcast_if(struct sock *sk, char *ifname){	struct net_device *dev;	struct inet_sock *inet = inet_sk(sk);	if ((dev = __dev_get_by_name(ifname)) == NULL)		return -ENODEV;	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)		return -EINVAL;	lock_sock(sk);	inet->mc_index = dev->ifindex;	/*  inet->mc_addr  = 0; */	release_sock(sk);	return 0;}/* *	Set the maximum length of sync message according to the *	specified interface's MTU. */static int set_sync_mesg_maxlen(int sync_state){	struct net_device *dev;	int num;	if (sync_state == IP_VS_STATE_MASTER) {		if ((dev = __dev_get_by_name(ip_vs_master_mcast_ifn)) == NULL)			return -ENODEV;		num = (dev->mtu - sizeof(struct iphdr) -		       sizeof(struct udphdr) -		       SYNC_MESG_HEADER_LEN - 20) / SIMPLE_CONN_SIZE;		sync_send_mesg_maxlen =			SYNC_MESG_HEADER_LEN + SIMPLE_CONN_SIZE * num;		IP_VS_DBG(7, "setting the maximum length of sync sending "			  "message %d.\n", sync_send_mesg_maxlen);	} else if (sync_state == IP_VS_STATE_BACKUP) {		if ((dev = __dev_get_by_name(ip_vs_backup_mcast_ifn)) == NULL)			return -ENODEV;		sync_recv_mesg_maxlen = dev->mtu -			sizeof(struct iphdr) - sizeof(struct udphdr);		IP_VS_DBG(7, "setting the maximum length of sync receiving "			  "message %d.\n", sync_recv_mesg_maxlen);	}	return 0;}/* *      Join a multicast group. *      the group is specified by a class D multicast address 224.0.0.0/8 *      in the in_addr structure passed in as a parameter. */static intjoin_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname){	struct ip_mreqn mreq;	struct net_device *dev;	int ret;	memset(&mreq, 0, sizeof(mreq));	memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));	if ((dev = __dev_get_by_name(ifname)) == NULL)		return -ENODEV;	if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)		return -EINVAL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -