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

📄 ip_vs_ctl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	rc = seq_open(file, &ip_vs_info_seq_ops);	if (rc)		goto out_kfree;	seq	     = file->private_data;	seq->private = s;	memset(s, 0, sizeof(*s));out:	return rc;out_kfree:	kfree(s);	goto out;}static struct file_operations ip_vs_info_fops = {	.owner	 = THIS_MODULE,	.open    = ip_vs_info_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release_private,};#endifstruct ip_vs_stats ip_vs_stats;#ifdef CONFIG_PROC_FSstatic int ip_vs_stats_show(struct seq_file *seq, void *v){/*               01234567 01234567 01234567 0123456701234567 0123456701234567 */	seq_puts(seq,		 "   Total Incoming Outgoing         Incoming         Outgoing\n");	seq_printf(seq,		   "   Conns  Packets  Packets            Bytes            Bytes\n");	spin_lock_bh(&ip_vs_stats.lock);	seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns,		   ip_vs_stats.inpkts, ip_vs_stats.outpkts,		   (unsigned long long) ip_vs_stats.inbytes,		   (unsigned long long) ip_vs_stats.outbytes);/*                 01234567 01234567 01234567 0123456701234567 0123456701234567 */	seq_puts(seq,		   " Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s\n");	seq_printf(seq,"%8X %8X %8X %16X %16X\n",			ip_vs_stats.cps,			ip_vs_stats.inpps,			ip_vs_stats.outpps,			ip_vs_stats.inbps,			ip_vs_stats.outbps);	spin_unlock_bh(&ip_vs_stats.lock);	return 0;}static int ip_vs_stats_seq_open(struct inode *inode, struct file *file){	return single_open(file, ip_vs_stats_show, NULL);}static struct file_operations ip_vs_stats_fops = {	.owner = THIS_MODULE,	.open = ip_vs_stats_seq_open,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};#endif/* *	Set timeout values for tcp tcpfin udp in the timeout_table. */static int ip_vs_set_timeout(struct ip_vs_timeout_user *u){	IP_VS_DBG(2, "Setting timeout tcp:%d tcpfin:%d udp:%d\n",		  u->tcp_timeout,		  u->tcp_fin_timeout,		  u->udp_timeout);#ifdef CONFIG_IP_VS_PROTO_TCP	if (u->tcp_timeout) {		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED]			= u->tcp_timeout * HZ;	}	if (u->tcp_fin_timeout) {		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT]			= u->tcp_fin_timeout * HZ;	}#endif#ifdef CONFIG_IP_VS_PROTO_UDP	if (u->udp_timeout) {		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL]			= u->udp_timeout * HZ;	}#endif	return 0;}#define SET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)#define SERVICE_ARG_LEN		(sizeof(struct ip_vs_service_user))#define SVCDEST_ARG_LEN		(sizeof(struct ip_vs_service_user) +	\				 sizeof(struct ip_vs_dest_user))#define TIMEOUT_ARG_LEN		(sizeof(struct ip_vs_timeout_user))#define DAEMON_ARG_LEN		(sizeof(struct ip_vs_daemon_user))#define MAX_ARG_LEN		SVCDEST_ARG_LENstatic const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {	[SET_CMDID(IP_VS_SO_SET_ADD)]		= SERVICE_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_EDIT)]		= SERVICE_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_DEL)]		= SERVICE_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_FLUSH)]		= 0,	[SET_CMDID(IP_VS_SO_SET_ADDDEST)]	= SVCDEST_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_DELDEST)]	= SVCDEST_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_EDITDEST)]	= SVCDEST_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_TIMEOUT)]	= TIMEOUT_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_STARTDAEMON)]	= DAEMON_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_STOPDAEMON)]	= DAEMON_ARG_LEN,	[SET_CMDID(IP_VS_SO_SET_ZERO)]		= SERVICE_ARG_LEN,};static intdo_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len){	int ret;	unsigned char arg[MAX_ARG_LEN];	struct ip_vs_service_user *usvc;	struct ip_vs_service *svc;	struct ip_vs_dest_user *udest;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (len != set_arglen[SET_CMDID(cmd)]) {		IP_VS_ERR("set_ctl: len %u != %u\n",			  len, set_arglen[SET_CMDID(cmd)]);		return -EINVAL;	}	if (copy_from_user(arg, user, len) != 0)		return -EFAULT;	/* increase the module use count */	ip_vs_use_count_inc();	if (down_interruptible(&__ip_vs_mutex)) {		ret = -ERESTARTSYS;		goto out_dec;	}	if (cmd == IP_VS_SO_SET_FLUSH) {		/* Flush the virtual service */		ret = ip_vs_flush();		goto out_unlock;	} else if (cmd == IP_VS_SO_SET_TIMEOUT) {		/* Set timeout values for (tcp tcpfin udp) */		ret = ip_vs_set_timeout((struct ip_vs_timeout_user *)arg);		goto out_unlock;	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;		ret = start_sync_thread(dm->state, dm->mcast_ifn, dm->syncid);		goto out_unlock;	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;		ret = stop_sync_thread(dm->state);		goto out_unlock;	}	usvc = (struct ip_vs_service_user *)arg;	udest = (struct ip_vs_dest_user *)(usvc + 1);	if (cmd == IP_VS_SO_SET_ZERO) {		/* if no service address is set, zero counters in all */		if (!usvc->fwmark && !usvc->addr && !usvc->port) {			ret = ip_vs_zero_all();			goto out_unlock;		}	}	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */	if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) {		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",			  usvc->protocol, NIPQUAD(usvc->addr),			  ntohs(usvc->port), usvc->sched_name);		ret = -EFAULT;		goto out_unlock;	}	/* Lookup the exact service by <protocol, addr, port> or fwmark */	if (usvc->fwmark == 0)		svc = __ip_vs_service_get(usvc->protocol,					  usvc->addr, usvc->port);	else		svc = __ip_vs_svc_fwm_get(usvc->fwmark);	if (cmd != IP_VS_SO_SET_ADD	    && (svc == NULL || svc->protocol != usvc->protocol)) {		ret = -ESRCH;		goto out_unlock;	}	switch (cmd) {	case IP_VS_SO_SET_ADD:		if (svc != NULL)			ret = -EEXIST;		else			ret = ip_vs_add_service(usvc, &svc);		break;	case IP_VS_SO_SET_EDIT:		ret = ip_vs_edit_service(svc, usvc);		break;	case IP_VS_SO_SET_DEL:		ret = ip_vs_del_service(svc);		if (!ret)			goto out_unlock;		break;	case IP_VS_SO_SET_ZERO:		ret = ip_vs_zero_service(svc);		break;	case IP_VS_SO_SET_ADDDEST:		ret = ip_vs_add_dest(svc, udest);		break;	case IP_VS_SO_SET_EDITDEST:		ret = ip_vs_edit_dest(svc, udest);		break;	case IP_VS_SO_SET_DELDEST:		ret = ip_vs_del_dest(svc, udest);		break;	default:		ret = -EINVAL;	}	if (svc)		ip_vs_service_put(svc);  out_unlock:	up(&__ip_vs_mutex);  out_dec:	/* decrease the module use count */	ip_vs_use_count_dec();	return ret;}static voidip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src){	spin_lock_bh(&src->lock);	memcpy(dst, src, (char*)&src->lock - (char*)src);	spin_unlock_bh(&src->lock);}static voidip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src){	dst->protocol = src->protocol;	dst->addr = src->addr;	dst->port = src->port;	dst->fwmark = src->fwmark;	strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));	dst->flags = src->flags;	dst->timeout = src->timeout / HZ;	dst->netmask = src->netmask;	dst->num_dests = src->num_dests;	ip_vs_copy_stats(&dst->stats, &src->stats);}static inline int__ip_vs_get_service_entries(const struct ip_vs_get_services *get,			    struct ip_vs_get_services __user *uptr){	int idx, count=0;	struct ip_vs_service *svc;	struct ip_vs_service_entry entry;	int ret = 0;	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {		list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {			if (count >= get->num_services)				goto out;			memset(&entry, 0, sizeof(entry));			ip_vs_copy_service(&entry, svc);			if (copy_to_user(&uptr->entrytable[count],					 &entry, sizeof(entry))) {				ret = -EFAULT;				goto out;			}			count++;		}	}	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {		list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {			if (count >= get->num_services)				goto out;			memset(&entry, 0, sizeof(entry));			ip_vs_copy_service(&entry, svc);			if (copy_to_user(&uptr->entrytable[count],					 &entry, sizeof(entry))) {				ret = -EFAULT;				goto out;			}			count++;		}	}  out:	return ret;}static inline int__ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,			 struct ip_vs_get_dests __user *uptr){	struct ip_vs_service *svc;	int ret = 0;	if (get->fwmark)		svc = __ip_vs_svc_fwm_get(get->fwmark);	else		svc = __ip_vs_service_get(get->protocol,					  get->addr, get->port);	if (svc) {		int count = 0;		struct ip_vs_dest *dest;		struct ip_vs_dest_entry entry;		list_for_each_entry(dest, &svc->destinations, n_list) {			if (count >= get->num_dests)				break;			entry.addr = dest->addr;			entry.port = dest->port;			entry.conn_flags = atomic_read(&dest->conn_flags);			entry.weight = atomic_read(&dest->weight);			entry.u_threshold = dest->u_threshold;			entry.l_threshold = dest->l_threshold;			entry.activeconns = atomic_read(&dest->activeconns);			entry.inactconns = atomic_read(&dest->inactconns);			entry.persistconns = atomic_read(&dest->persistconns);			ip_vs_copy_stats(&entry.stats, &dest->stats);			if (copy_to_user(&uptr->entrytable[count],					 &entry, sizeof(entry))) {				ret = -EFAULT;				break;			}			count++;		}		ip_vs_service_put(svc);	} else		ret = -ESRCH;	return ret;}static inline void__ip_vs_get_timeouts(struct ip_vs_timeout_user *u){#ifdef CONFIG_IP_VS_PROTO_TCP	u->tcp_timeout =		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED] / HZ;	u->tcp_fin_timeout =		ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT] / HZ;#endif#ifdef CONFIG_IP_VS_PROTO_UDP	u->udp_timeout =		ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL] / HZ;#endif}#define GET_CMDID(cmd)		(cmd - IP_VS_BASE_CTL)#define GET_INFO_ARG_LEN	(sizeof(struct ip_vs_getinfo))#define GET_SERVICES_ARG_LEN	(sizeof(struct ip_vs_get_services))#define GET_SERVICE_ARG_LEN	(sizeof(struct ip_vs_service_entry))#define GET_DESTS_ARG_LEN	(sizeof(struct ip_vs_get_dests))#define GET_TIMEOUT_ARG_LEN	(sizeof(struct ip_vs_timeout_user))#define GET_DAEMON_ARG_LEN	(sizeof(struct ip_vs_daemon_user) * 2)static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {	[GET_CMDID(IP_VS_SO_GET_VERSION)]	= 64,	[GET_CMDID(IP_VS_SO_GET_INFO)]		= GET_INFO_ARG_LEN,	[GET_CMDID(IP_VS_SO_GET_SERVICES)]	= GET_SERVICES_ARG_LEN,	[GET_CMDID(IP_VS_SO_GET_SERVICE)]	= GET_SERVICE_ARG_LEN,	[GET_CMDID(IP_VS_SO_GET_DESTS)]		= GET_DESTS_ARG_LEN,	[GET_CMDID(IP_VS_SO_GET_TIMEOUT)]	= GET_TIMEOUT_ARG_LEN,	[GET_CMDID(IP_VS_SO_GET_DAEMON)]	= GET_DAEMON_ARG_LEN,};static intdo_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len){	unsigned char arg[128];	int ret = 0;	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (*len < get_arglen[GET_CMDID(cmd)]) {		IP_VS_ERR("get_ctl: len %u < %u\n",			  *len, get_arglen[GET_CMDID(cmd)]);		return -EINVAL;	}	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)		return -EFAULT;	if (down_interruptible(&__ip_vs_mutex))		return -ERESTARTSYS;	switch (cmd) {	case IP_VS_SO_GET_VERSION:	{		char buf[64];		sprintf(buf, "IP Virtual Server version %d.%d.%d (size=%d)",			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);		if (copy_to_user(user, buf, strlen(buf)+1) != 0) {			ret = -EFAULT;			goto out;		}		*len = strlen(buf)+1;	}	break;	case IP_VS_SO_GET_INFO:	{		struct ip_vs_getinfo info;		info.version = IP_VS_VERSION_CODE;		info.size = IP_VS_CONN_TAB_SIZE;		info.num_services = ip_vs_num_services;		if (copy_to_user(user, &info, sizeof(info)) != 0)			ret = -EFAULT;	}	break;	case IP_VS_SO_GET_SERVICES:	{		struct ip_vs_get_services *get;		int size;		get = (struct ip_vs_get_services *)arg;		size = sizeof(*get) +			sizeof(struct ip_vs_service_entry) * get->num_services;		if (*len != size) {			IP_VS_ERR("length: %u != %u\n", *len, size);			ret = -EINVAL;			goto out;		}		ret = __ip_vs_get_service_entries(get, user);	}	break;	case IP_VS_SO_GET_SERVICE:	{		struct ip_vs_service_entry *entry;		struct ip_vs_service *svc;		entry = (struct ip_vs_service_entry *)arg;		if (entry->fwmark)			svc = __ip_vs_svc_fwm_get(entry->fwmark);		else			svc = __ip_vs_service_get(entry->protocol,						  entry->addr, entry->port);		if (svc) {			ip_vs_copy_service(entry, svc);			if (copy_to_user(user, entry, sizeof(*entry)) != 0)				ret = -EFAULT;			ip_vs_service_put(svc);		} else			ret = -ESRCH;	}	break;	case IP_VS_SO_GET_DESTS:	{		struct ip_vs_get_dests *get;		int size;		get = (struct ip_vs_get_dests *)arg;		size = sizeof(*get) +			sizeof(struct ip_vs_dest_entry) * get->num_dests;		if (*len != size) {			IP_VS_ERR("length: %u != %u\n", *len, size);			ret = -EINVAL;			goto out;		}		ret = __ip_vs_get_dest_entries(get, user);	}	break;	case IP_VS_SO_GET_TIMEOUT:	{		struct ip_vs_timeout_user t;		__ip_vs_get_timeouts(&t);		if (copy_to_user(user, &t, sizeof(t)) != 0)			ret = -EFAULT;	}	break;	case IP_VS_SO_GET_DAEMON:	{		struct ip_vs_daemon_user d[2];		memset(&d, 0, sizeof(d));		if (ip_vs_sync_state & IP_VS_STATE_MASTER) {			d[0].state = IP_VS_STATE_MASTER;			strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));			d[0].syncid = ip_vs_master_syncid;		}		if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {			d[1].state = IP_VS_STATE_BACKUP;			strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));			d[1].syncid = ip_vs_backup_syncid;		}		if (copy_to_user(user, &d, sizeof(d)) != 0)			ret = -EFAULT;	}	break;	default:		ret = -EINVAL;	}  out:	up(&__ip_vs_mutex);	return ret;}static struct nf_sockopt_ops ip_vs_sockopts = {	.pf		= PF_INET,	.set_optmin	= IP_VS_BASE_CTL,	.set_optmax	= IP_VS_SO_SET_MAX+1,	.set		= do_ip_vs_set_ctl,	.get_optmin	= IP_VS_BASE_CTL,	.get_optmax	= IP_VS_SO_GET_MAX+1,	.get		= do_ip_vs_get_ctl,};int ip_vs_control_init(void){	int ret;	int idx;	EnterFunction(2);	ret = nf_register_sockopt(&ip_vs_sockopts);	if (ret) {		IP_VS_ERR("cannot register sockopt.\n");		return ret;	}	proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops);	proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops);	sysctl_header = register_sysctl_table(vs_root_table, 0);	/* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++)  {		INIT_LIST_HEAD(&ip_vs_svc_table[idx]);		INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);	}	for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++)  {		INIT_LIST_HEAD(&ip_vs_rtable[idx]);	}	memset(&ip_vs_stats, 0, sizeof(ip_vs_stats));	spin_lock_init(&ip_vs_stats.lock);	ip_vs_new_estimator(&ip_vs_stats);	/* Hook the defense timer */	schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD);	LeaveFunction(2);	return 0;}void ip_vs_control_cleanup(void){	EnterFunction(2);	ip_vs_trash_cleanup();	cancel_rearming_delayed_work(&defense_work);	ip_vs_kill_estimator(&ip_vs_stats);	unregister_sysctl_table(sysctl_header);	proc_net_remove("ip_vs_stats");	proc_net_remove("ip_vs");	nf_unregister_sockopt(&ip_vs_sockopts);	LeaveFunction(2);}

⌨️ 快捷键说明

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