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

📄 ip_vs_conn.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * dest will be either in service's destination list	 * or in the trash.	 */	atomic_dec(&dest->refcnt);}/* *	Checking if the destination of a connection template is available. *	If available, return 1, otherwise invalidate this connection *	template and return 0. */int ip_vs_check_template(struct ip_vs_conn *ct){	struct ip_vs_dest *dest = ct->dest;	/*	 * Checking the dest server status.	 */	if ((dest == NULL) ||	    !(dest->flags & IP_VS_DEST_F_AVAILABLE) || 	    (sysctl_ip_vs_expire_quiescent_template && 	     (atomic_read(&dest->weight) == 0))) {		IP_VS_DBG(9, "check_template: dest not available for "			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "			  "-> d:%u.%u.%u.%u:%d\n",			  ip_vs_proto_name(ct->protocol),			  NIPQUAD(ct->caddr), ntohs(ct->cport),			  NIPQUAD(ct->vaddr), ntohs(ct->vport),			  NIPQUAD(ct->daddr), ntohs(ct->dport));		/*		 * Invalidate the connection template		 */		if (ct->vport != 65535) {			if (ip_vs_conn_unhash(ct)) {				ct->dport = 65535;				ct->vport = 65535;				ct->cport = 0;				ip_vs_conn_hash(ct);			}		}		/*		 * Simply decrease the refcnt of the template,		 * don't restart its timer.		 */		atomic_dec(&ct->refcnt);		return 0;	}	return 1;}static void ip_vs_conn_expire(unsigned long data){	struct ip_vs_conn *cp = (struct ip_vs_conn *)data;	cp->timeout = 60*HZ;	/*	 *	hey, I'm using it	 */	atomic_inc(&cp->refcnt);	/*	 *	do I control anybody?	 */	if (atomic_read(&cp->n_control))		goto expire_later;	/*	 *	unhash it if it is hashed in the conn table	 */	if (!ip_vs_conn_unhash(cp))		goto expire_later;	/*	 *	refcnt==1 implies I'm the only one referrer	 */	if (likely(atomic_read(&cp->refcnt) == 1)) {		/* delete the timer if it is activated by other users */		if (timer_pending(&cp->timer))			del_timer(&cp->timer);		/* does anybody control me? */		if (cp->control)			ip_vs_control_del(cp);		if (unlikely(cp->app != NULL))			ip_vs_unbind_app(cp);		ip_vs_unbind_dest(cp);		if (cp->flags & IP_VS_CONN_F_NO_CPORT)			atomic_dec(&ip_vs_conn_no_cport_cnt);		atomic_dec(&ip_vs_conn_count);		kmem_cache_free(ip_vs_conn_cachep, cp);		return;	}	/* hash it back to the table */	ip_vs_conn_hash(cp);  expire_later:	IP_VS_DBG(7, "delayed: refcnt-1=%d conn.n_control=%d\n",		  atomic_read(&cp->refcnt)-1,		  atomic_read(&cp->n_control));	ip_vs_conn_put(cp);}void ip_vs_conn_expire_now(struct ip_vs_conn *cp){	if (del_timer(&cp->timer))		mod_timer(&cp->timer, jiffies);}/* *	Create a new connection entry and hash it into the ip_vs_conn_tab */struct ip_vs_conn *ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,	       __u32 daddr, __u16 dport, unsigned flags,	       struct ip_vs_dest *dest){	struct ip_vs_conn *cp;	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);	cp = kmem_cache_alloc(ip_vs_conn_cachep, GFP_ATOMIC);	if (cp == NULL) {		IP_VS_ERR_RL("ip_vs_conn_new: no memory available.\n");		return NULL;	}	memset(cp, 0, sizeof(*cp));	INIT_LIST_HEAD(&cp->c_list);	init_timer(&cp->timer);	cp->timer.data     = (unsigned long)cp;	cp->timer.function = ip_vs_conn_expire;	cp->protocol	   = proto;	cp->caddr	   = caddr;	cp->cport	   = cport;	cp->vaddr	   = vaddr;	cp->vport	   = vport;	cp->daddr          = daddr;	cp->dport          = dport;	cp->flags	   = flags;	spin_lock_init(&cp->lock);	/*	 * Set the entry is referenced by the current thread before hashing	 * it in the table, so that other thread run ip_vs_random_dropentry	 * but cannot drop this entry.	 */	atomic_set(&cp->refcnt, 1);	atomic_set(&cp->n_control, 0);	atomic_set(&cp->in_pkts, 0);	atomic_inc(&ip_vs_conn_count);	if (flags & IP_VS_CONN_F_NO_CPORT)		atomic_inc(&ip_vs_conn_no_cport_cnt);	/* Bind the connection with a destination server */	ip_vs_bind_dest(cp, dest);	/* Set its state and timeout */	cp->state = 0;	cp->timeout = 3*HZ;	/* Bind its packet transmitter */	ip_vs_bind_xmit(cp);	if (unlikely(pp && atomic_read(&pp->appcnt)))		ip_vs_bind_app(cp, pp);	/* Hash it in the ip_vs_conn_tab finally */	ip_vs_conn_hash(cp);	return cp;}/* *	/proc/net/ip_vs_conn entries */#ifdef CONFIG_PROC_FSstatic void *ip_vs_conn_array(struct seq_file *seq, loff_t pos){	int idx;	struct ip_vs_conn *cp;		for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {		ct_read_lock_bh(idx);		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {			if (pos-- == 0) {				seq->private = &ip_vs_conn_tab[idx];				return cp;			}		}		ct_read_unlock_bh(idx);	}	return NULL;}static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos){	seq->private = NULL;	return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;}static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct ip_vs_conn *cp = v;	struct list_head *e, *l = seq->private;	int idx;	++*pos;	if (v == SEQ_START_TOKEN) 		return ip_vs_conn_array(seq, 0);	/* more on same hash chain? */	if ((e = cp->c_list.next) != l)		return list_entry(e, struct ip_vs_conn, c_list);	idx = l - ip_vs_conn_tab;	ct_read_unlock_bh(idx);	while (++idx < IP_VS_CONN_TAB_SIZE) {		ct_read_lock_bh(idx);		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {			seq->private = &ip_vs_conn_tab[idx];			return cp;		}			ct_read_unlock_bh(idx);	}	seq->private = NULL;	return NULL;}static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v){	struct list_head *l = seq->private;	if (l)		ct_read_unlock_bh(l - ip_vs_conn_tab);}static int ip_vs_conn_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN)		seq_puts(seq,   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires\n");	else {		const struct ip_vs_conn *cp = v;		seq_printf(seq,			"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",				ip_vs_proto_name(cp->protocol),				ntohl(cp->caddr), ntohs(cp->cport),				ntohl(cp->vaddr), ntohs(cp->vport),				ntohl(cp->daddr), ntohs(cp->dport),				ip_vs_state_name(cp->protocol, cp->state),				(cp->timer.expires-jiffies)/HZ);	}	return 0;}static struct seq_operations ip_vs_conn_seq_ops = {	.start = ip_vs_conn_seq_start,	.next  = ip_vs_conn_seq_next,	.stop  = ip_vs_conn_seq_stop,	.show  = ip_vs_conn_seq_show,};static int ip_vs_conn_open(struct inode *inode, struct file *file){	return seq_open(file, &ip_vs_conn_seq_ops);}static struct file_operations ip_vs_conn_fops = {	.owner	 = THIS_MODULE,	.open    = ip_vs_conn_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release,};#endif/* *      Randomly drop connection entries before running out of memory */static inline int todrop_entry(struct ip_vs_conn *cp){	/*	 * The drop rate array needs tuning for real environments.	 * Called from timer bh only => no locking	 */	static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};	static char todrop_counter[9] = {0};	int i;	/* if the conn entry hasn't lasted for 60 seconds, don't drop it.	   This will leave enough time for normal connection to get	   through. */	if (time_before(cp->timeout + jiffies, cp->timer.expires + 60*HZ))		return 0;	/* Don't drop the entry if its number of incoming packets is not	   located in [0, 8] */	i = atomic_read(&cp->in_pkts);	if (i > 8 || i < 0) return 0;	if (!todrop_rate[i]) return 0;	if (--todrop_counter[i] > 0) return 0;	todrop_counter[i] = todrop_rate[i];	return 1;}/* Called from keventd and must protect itself from softirqs */void ip_vs_random_dropentry(void){	int idx;	struct ip_vs_conn *cp;	/*	 * Randomly scan 1/32 of the whole table every second	 */	for (idx = 0; idx < (IP_VS_CONN_TAB_SIZE>>5); idx++) {		unsigned hash = net_random() & IP_VS_CONN_TAB_MASK;		/*		 *  Lock is actually needed in this loop.		 */		ct_write_lock_bh(hash);		list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {			if (cp->flags & IP_VS_CONN_F_TEMPLATE)				/* connection template */				continue;			if (cp->protocol == IPPROTO_TCP) {				switch(cp->state) {				case IP_VS_TCP_S_SYN_RECV:				case IP_VS_TCP_S_SYNACK:					break;				case IP_VS_TCP_S_ESTABLISHED:					if (todrop_entry(cp))						break;					continue;				default:					continue;				}			} else {				if (!todrop_entry(cp))					continue;			}			IP_VS_DBG(4, "del connection\n");			ip_vs_conn_expire_now(cp);			if (cp->control) {				IP_VS_DBG(4, "del conn template\n");				ip_vs_conn_expire_now(cp->control);			}		}		ct_write_unlock_bh(hash);	}}/* *      Flush all the connection entries in the ip_vs_conn_tab */static void ip_vs_conn_flush(void){	int idx;	struct ip_vs_conn *cp;  flush_again:	for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {		/*		 *  Lock is actually needed in this loop.		 */		ct_write_lock_bh(idx);		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {			IP_VS_DBG(4, "del connection\n");			ip_vs_conn_expire_now(cp);			if (cp->control) {				IP_VS_DBG(4, "del conn template\n");				ip_vs_conn_expire_now(cp->control);			}		}		ct_write_unlock_bh(idx);	}	/* the counter may be not NULL, because maybe some conn entries	   are run by slow timer handler or unhashed but still referred */	if (atomic_read(&ip_vs_conn_count) != 0) {		schedule();		goto flush_again;	}}int ip_vs_conn_init(void){	int idx;	/*	 * Allocate the connection hash table and initialize its list heads	 */	ip_vs_conn_tab = vmalloc(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head));	if (!ip_vs_conn_tab)		return -ENOMEM;	/* Allocate ip_vs_conn slab cache */	ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",					      sizeof(struct ip_vs_conn), 0,					      SLAB_HWCACHE_ALIGN, NULL, NULL);	if (!ip_vs_conn_cachep) {		vfree(ip_vs_conn_tab);		return -ENOMEM;	}	IP_VS_INFO("Connection hash table configured "		   "(size=%d, memory=%ldKbytes)\n",		   IP_VS_CONN_TAB_SIZE,		   (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024);	IP_VS_DBG(0, "Each connection entry needs %Zd bytes at least\n",		  sizeof(struct ip_vs_conn));	for (idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {		INIT_LIST_HEAD(&ip_vs_conn_tab[idx]);	}	for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++)  {		rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);	}	proc_net_fops_create("ip_vs_conn", 0, &ip_vs_conn_fops);	/* calculate the random value for connection hash */	get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));	return 0;}void ip_vs_conn_cleanup(void){	/* flush all the connection entries first */	ip_vs_conn_flush();	/* Release the empty cache */	kmem_cache_destroy(ip_vs_conn_cachep);	proc_net_remove("ip_vs_conn");	vfree(ip_vs_conn_tab);}

⌨️ 快捷键说明

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