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

📄 ip_vs_core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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_core.c,v 1.31.2.5 2003/07/29 14:37:12 wensong Exp $ * * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org> *              Peter Kese <peter.kese@ijs.si> *              Julian Anastasov <ja@ssi.bg> * *              This program is free software; you can redistribute it and/or *              modify it under the terms of the GNU General Public License *              as published by the Free Software Foundation; either version *              2 of the License, or (at your option) any later version. * * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese, * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms * and others. * * Changes: * */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/icmp.h>#include <net/ip.h>#include <net/tcp.h>#include <net/udp.h>#include <net/icmp.h>                   /* for icmp_send */#include <net/route.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <net/ip_vs.h>EXPORT_SYMBOL(register_ip_vs_scheduler);EXPORT_SYMBOL(unregister_ip_vs_scheduler);EXPORT_SYMBOL(ip_vs_skb_replace);EXPORT_SYMBOL(ip_vs_proto_name);EXPORT_SYMBOL(ip_vs_conn_new);EXPORT_SYMBOL(ip_vs_conn_in_get);EXPORT_SYMBOL(ip_vs_conn_out_get);EXPORT_SYMBOL(ip_vs_conn_listen);EXPORT_SYMBOL(ip_vs_conn_put);#ifdef CONFIG_IP_VS_DEBUGEXPORT_SYMBOL(ip_vs_get_debug_level);#endifEXPORT_SYMBOL(check_for_ip_vs_out);/* ID used in ICMP lookups */#define icmp_id(icmph)          ((icmph->un).echo.id)const char *ip_vs_proto_name(unsigned proto){	static char buf[20];	switch (proto) {	case IPPROTO_IP:		return "IP";	case IPPROTO_UDP:		return "UDP";	case IPPROTO_TCP:		return "TCP";	case IPPROTO_ICMP:		return "ICMP";	default:		sprintf(buf, "IP_%d", proto);		return buf;	}}static inline voidip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb){	struct ip_vs_dest *dest = cp->dest;	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {		spin_lock(&dest->stats.lock);		dest->stats.inpkts++;		dest->stats.inbytes += skb->len;		spin_unlock(&dest->stats.lock);		spin_lock(&dest->svc->stats.lock);		dest->svc->stats.inpkts++;		dest->svc->stats.inbytes += skb->len;		spin_unlock(&dest->svc->stats.lock);		spin_lock(&ip_vs_stats.lock);		ip_vs_stats.inpkts++;		ip_vs_stats.inbytes += skb->len;		spin_unlock(&ip_vs_stats.lock);	}}static inline voidip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb){	struct ip_vs_dest *dest = cp->dest;	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {		spin_lock(&dest->stats.lock);		dest->stats.outpkts++;		dest->stats.outbytes += skb->len;		spin_unlock(&dest->stats.lock);		spin_lock(&dest->svc->stats.lock);		dest->svc->stats.outpkts++;		dest->svc->stats.outbytes += skb->len;		spin_unlock(&dest->svc->stats.lock);		spin_lock(&ip_vs_stats.lock);		ip_vs_stats.outpkts++;		ip_vs_stats.outbytes += skb->len;		spin_unlock(&ip_vs_stats.lock);	}}static inline voidip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc){	spin_lock(&cp->dest->stats.lock);	cp->dest->stats.conns++;	spin_unlock(&cp->dest->stats.lock);	spin_lock(&svc->stats.lock);	svc->stats.conns++;	spin_unlock(&svc->stats.lock);	spin_lock(&ip_vs_stats.lock);	ip_vs_stats.conns++;	spin_unlock(&ip_vs_stats.lock);}/* *  IPVS persistent scheduling function *  It creates a connection entry according to its template if exists, *  or selects a server and creates a connection entry plus a template. *  Locking: we are svc user (svc->refcnt), so we hold all dests too */static struct ip_vs_conn *ip_vs_sched_persist(struct ip_vs_service *svc, struct iphdr *iph){	struct ip_vs_conn *cp = NULL;	struct ip_vs_dest *dest;	const __u16 *portp;	struct ip_vs_conn *ct;	__u16  dport;	 /* destination port to forward */	__u32  snet;	 /* source network of the client, after masking */	portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);	/* Mask saddr with the netmask to adjust template granularity */	snet = iph->saddr & svc->netmask;	IP_VS_DBG(6, "P-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "		  "mnet %u.%u.%u.%u\n",		  NIPQUAD(iph->saddr), ntohs(portp[0]),		  NIPQUAD(iph->daddr), ntohs(portp[1]),		  NIPQUAD(snet));	/*	 * As far as we know, FTP is a very complicated network protocol, and	 * it uses control connection and data connections. For active FTP,	 * FTP server initialize data connection to the client, its source port	 * is often 20. For passive FTP, FTP server tells the clients the port	 * that it passively listens to,  and the client issues the data	 * connection. In the tunneling or direct routing mode, the load	 * balancer is on the client-to-server half of connection, the port	 * number is unknown to the load balancer. So, a conn template like	 * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>	 * is created for other persistent services.	 */	if (portp[1] == svc->port) {		/* Check if a template already exists */		if (svc->port != FTPPORT)			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,					       iph->daddr, portp[1]);		else			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,					       iph->daddr, 0);		if (!ct || !ip_vs_check_template(ct)) {			/*			 * No template found or the dest of the connection			 * template is not available.			 */			dest = svc->scheduler->schedule(svc, iph);			if (dest == NULL) {				IP_VS_DBG(1, "P-schedule: no dest found.\n");				return NULL;			}			/*			 * Create a template like <protocol,caddr,0,			 * vaddr,vport,daddr,dport> for non-ftp service,			 * and <protocol,caddr,0,vaddr,0,daddr,0>			 * for ftp service.			 */			if (svc->port != FTPPORT)				ct = ip_vs_conn_new(iph->protocol,						    snet, 0,						    iph->daddr, portp[1],						    dest->addr, dest->port,						    0,						    dest);			else				ct = ip_vs_conn_new(iph->protocol,						    snet, 0,						    iph->daddr, 0,						    dest->addr, 0,						    0,						    dest);			if (ct == NULL)				return NULL;			ct->timeout = svc->timeout;		} else {			/* set destination with the found template */			dest = ct->dest;		}		dport = dest->port;	} else {		/*		 * Note: persistent fwmark-based services and persistent		 * port zero service are handled here.		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>		 */		if (svc->fwmark)			ct = ip_vs_conn_in_get(IPPROTO_IP, snet, 0,					       htonl(svc->fwmark), 0);		else			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,					       iph->daddr, 0);		if (!ct || !ip_vs_check_template(ct)) {			/*			 * If it is not persistent port zero, return NULL,			 * otherwise create a connection template.			 */			if (svc->port)				return NULL;			dest = svc->scheduler->schedule(svc, iph);			if (dest == NULL) {				IP_VS_DBG(1, "P-schedule: no dest found.\n");				return NULL;			}			/*			 * Create a template according to the service			 */			if (svc->fwmark)				ct = ip_vs_conn_new(IPPROTO_IP,						    snet, 0,						    htonl(svc->fwmark), 0,						    dest->addr, 0,						    0,						    dest);			else				ct = ip_vs_conn_new(iph->protocol,						    snet, 0,						    iph->daddr, 0,						    dest->addr, 0,						    0,						    dest);			if (ct == NULL)				return NULL;			ct->timeout = svc->timeout;		} else {			/* set destination with the found template */			dest = ct->dest;		}		dport = portp[1];	}	/*	 *    Create a new connection according to the template	 */	cp = ip_vs_conn_new(iph->protocol,			    iph->saddr, portp[0],			    iph->daddr, portp[1],			    dest->addr, dport,			    0,			    dest);	if (cp == NULL) {		ip_vs_conn_put(ct);		return NULL;	}	/*	 *    Increase the inactive connection counter	 *    because it is in Syn-Received	 *    state (inactive) when the connection is created.	 */	atomic_inc(&dest->inactconns);	/*	 *    Add its control	 */	ip_vs_control_add(cp, ct);	ip_vs_conn_put(ct);	return cp;}/* *  IPVS main scheduling function *  It selects a server according to the virtual service, and *  creates a connection entry. */static struct ip_vs_conn *ip_vs_schedule(struct ip_vs_service *svc, struct iphdr *iph){	struct ip_vs_conn *cp = NULL;	struct ip_vs_dest *dest;	const __u16 *portp;	/*	 *    Persistent service	 */	if (svc->flags & IP_VS_SVC_F_PERSISTENT)		return ip_vs_sched_persist(svc, iph);	/*	 *    Non-persistent service	 */	portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);	if (!svc->fwmark && portp[1] != svc->port) {		if (!svc->port)			IP_VS_ERR("Schedule: port zero only supported "				  "in persistent services, "				  "check your ipvs configuration\n");		return NULL;	}	dest = svc->scheduler->schedule(svc, iph);	if (dest == NULL) {		IP_VS_DBG(1, "Schedule: no dest found.\n");		return NULL;	}	/*	 *    Create a connection entry.	 */	cp = ip_vs_conn_new(iph->protocol,			    iph->saddr, portp[0],			    iph->daddr, portp[1],			    dest->addr, dest->port?dest->port:portp[1],			    0,			    dest);	if (cp == NULL)		return NULL;	/*	 *    Increase the inactive connection counter because it is in	 *    Syn-Received state (inactive) when the connection is created.	 */	atomic_inc(&dest->inactconns);	IP_VS_DBG(6, "Schedule fwd:%c s:%s c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "		  "d:%u.%u.%u.%u:%u flg:%X cnt:%d\n",		  ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state),		  NIPQUAD(cp->caddr), ntohs(cp->cport),		  NIPQUAD(cp->vaddr), ntohs(cp->vport),		  NIPQUAD(cp->daddr), ntohs(cp->dport),		  cp->flags, atomic_read(&cp->refcnt));	return cp;}/* *  Pass or drop the packet. *  Called by ip_vs_in, when the virtual service is available but *  no destination is available for a new connection. */static int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	__u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);	/* if it is fwmark-based service, the cache_bypass sysctl is up	   and the destination is RTN_UNICAST (and not local), then create	   a cache_bypass connection entry */	if (sysctl_ip_vs_cache_bypass && svc->fwmark	    && (inet_addr_type(iph->daddr) == RTN_UNICAST)) {		int ret;		struct ip_vs_conn *cp;		ip_vs_service_put(svc);		/* create a new connection entry */		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");		cp = ip_vs_conn_new(iph->protocol,				    iph->saddr, portp[0],				    iph->daddr, portp[1],				    0, 0,				    IP_VS_CONN_F_BYPASS,				    NULL);		if (cp == NULL) {			kfree_skb(skb);			return NF_STOLEN;		}		/* statistics */		ip_vs_in_stats(cp, skb);		/* set state */		ip_vs_set_state(cp, VS_STATE_INPUT, iph, portp);		/* transmit the first SYN packet */

⌨️ 快捷键说明

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