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

📄 shaper.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *			Simple traffic shaper for Linux NET3. * *	(c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved. *				http://www.cymru.net * *	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. *	 *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide  *	warranty for any of this software. This material is provided  *	"AS-IS" and at no charge.	 * *	 *	Algorithm: * *	Queue Frame: *		Compute time length of frame at regulated speed *		Add frame to queue at appropriate point *		Adjust time length computation for followup frames *		Any frame that falls outside of its boundaries is freed * *	We work to the following constants * *		SHAPER_QLEN	Maximum queued frames *		SHAPER_LATENCY	Bounding latency on a frame. Leaving this latency *				window drops the frame. This stops us queueing  *				frames for a long time and confusing a remote *				host. *		SHAPER_MAXSLIP	Maximum time a priority frame may jump forward. *				That bounds the penalty we will inflict on low *				priority traffic. *		SHAPER_BURST	Time range we call "now" in order to reduce *				system load. The more we make this the burstier *				the behaviour, the better local performance you *				get through packet clustering on routers and the *				worse the remote end gets to judge rtts. * *	This is designed to handle lower speed links ( < 200K/second or so). We *	run off a 100-150Hz base clock typically. This gives us a resolution at *	200Kbit/second of about 2Kbit or 256 bytes. Above that our timer *	resolution may start to cause much more burstiness in the traffic. We *	could avoid a lot of that by calling kick_shaper() at the end of the  *	tied device transmissions. If you run above about 100K second you  *	may need to tune the supposed speed rate for the right values. * *	BUGS: *		Downing the interface under the shaper before the shaper *		will render your machine defunct. Don't for now shape over *		PPP or SLIP therefore! *		This will be fixed in BETA4 */ /* * bh_atomic() SMP races fixes and rewritten the locking code to be SMP safe * and irq-mask friendly. NOTE: we can't use start_bh_atomic() in kick_shaper() * because it's going to be recalled from an irq handler, and synchronize_bh() * is a nono if called from irq context. *						1999  Andrea Arcangeli */ #include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/init.h>#include <net/dst.h>#include <net/arp.h>#include <linux/if_shaper.h>int sh_debug;		/* Debug flag */#define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"/* *	Locking */ static int shaper_lock(struct shaper *sh){	/*	 *	Lock in an interrupt must fail	 */	while (test_and_set_bit(0, &sh->locked))	{		if (!in_interrupt())			sleep_on(&sh->wait_queue);		else			return 0;				}	return 1;}static void shaper_kick(struct shaper *sh);static void shaper_unlock(struct shaper *sh){	clear_bit(0, &sh->locked);	wake_up(&sh->wait_queue);	shaper_kick(sh);}/* *	Compute clocks on a buffer */  static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb){ 	int t=skb->len/shaper->bytespertick; 	return t;}/* *	Set the speed of a shaper. We compute this in bytes per tick since *	thats how the machine wants to run. Quoted input is in bits per second *	as is traditional (note not BAUD). We assume 8 bit bytes.  */  static void shaper_setspeed(struct shaper *shaper, int bitspersec){	shaper->bitspersec=bitspersec;	shaper->bytespertick=(bitspersec/HZ)/8;	if(!shaper->bytespertick)		shaper->bytespertick++;}/* *	Throw a frame at a shaper. */  static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb){ 	struct sk_buff *ptr; 	 	/* 	 *	Get ready to work on this shaper. Lock may fail if its 	 *	an interrupt and locked. 	 */ 	  	if(!shaper_lock(shaper)) 		return -1; 	ptr=shaper->sendq.prev; 	 	/* 	 *	Set up our packet details 	 */ 	  	skb->shapelatency=0; 	skb->shapeclock=shaper->recovery; 	if(time_before(skb->shapeclock, jiffies)) 		skb->shapeclock=jiffies; 	skb->priority=0;	/* short term bug fix */ 	skb->shapestamp=jiffies; 	 	/* 	 *	Time slots for this packet. 	 */ 	  	skb->shapelen= shaper_clocks(shaper,skb); 	#ifdef SHAPER_COMPLEX /* and broken.. */ 	while(ptr && ptr!=(struct sk_buff *)&shaper->sendq) 	{ 		if(ptr->pri<skb->pri  			&& jiffies - ptr->shapeclock < SHAPER_MAXSLIP) 		{ 			struct sk_buff *tmp=ptr->prev; 			/* 			 *	It goes before us therefore we slip the length 			 *	of the new frame. 			 */ 			ptr->shapeclock+=skb->shapelen; 			ptr->shapelatency+=skb->shapelen; 			/* 			 *	The packet may have slipped so far back it 			 *	fell off. 			 */ 			if(ptr->shapelatency > SHAPER_LATENCY) 			{ 				skb_unlink(ptr); 				dev_kfree_skb(ptr); 			} 			ptr=tmp; 		} 		else 			break; 	} 	if(ptr==NULL || ptr==(struct sk_buff *)&shaper->sendq) 		skb_queue_head(&shaper->sendq,skb); 	else 	{ 		struct sk_buff *tmp; 		/* 		 *	Set the packet clock out time according to the 		 *	frames ahead. Im sure a bit of thought could drop 		 *	this loop. 		 */ 		for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next) 			skb->shapeclock+=tmp->shapelen; 		skb_append(ptr,skb); 	}#else	{		struct sk_buff *tmp;		/*		 *	Up our shape clock by the time pending on the queue		 *	(Should keep this in the shaper as a variable..)		 */		for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && 			tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)			skb->shapeclock+=tmp->shapelen;		/*		 *	Queue over time. Spill packet.		 */		if(skb->shapeclock-jiffies > SHAPER_LATENCY)			dev_kfree_skb(skb);		else			skb_queue_tail(&shaper->sendq, skb);	}#endif 	 	if(sh_debug) 		printk("Frame queued.\n"); 	if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) 	{ 		ptr=skb_dequeue(&shaper->sendq); 		dev_kfree_skb(ptr); 	} 	shaper_unlock(shaper); 	return 0;}/* *	Transmit from a shaper */ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb){	struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);	if(sh_debug)		printk("Kick frame on %p\n",newskb);	if(newskb)	{		newskb->dev=shaper->dev;		newskb->priority=2;		if(sh_debug)			printk("Kick new frame to %s, %d\n",				shaper->dev->name,newskb->priority);		dev_queue_xmit(newskb);		if(sh_debug)			printk("Kicked new frame out.\n");		dev_kfree_skb(skb);	}}/* *	Timer handler for shaping clock */ static void shaper_timer(unsigned long data){	struct shaper *sh=(struct shaper *)data;	shaper_kick(sh);}/* *	Kick a shaper queue and try and do something sensible with the  *	queue.  */static void shaper_kick(struct shaper *shaper){	struct sk_buff *skb;		/*	 *	Shaper unlock will kick	 */	 	if (test_and_set_bit(0, &shaper->locked))	{		if(sh_debug)			printk("Shaper locked.\n");		mod_timer(&shaper->timer, jiffies);		return;	}			/*	 *	Walk the list (may be empty)	 */	 	while((skb=skb_peek(&shaper->sendq))!=NULL)	{		/*		 *	Each packet due to go out by now (within an error		 *	of SHAPER_BURST) gets kicked onto the link 		 */		 		if(sh_debug)			printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);		if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST))		{			/*			 *	Pull the frame and get interrupts back on.			 */			 			skb_unlink(skb);			if (shaper->recovery < skb->shapeclock + skb->shapelen)				shaper->recovery = skb->shapeclock + skb->shapelen;			/*			 *	Pass on to the physical target device via			 *	our low level packet thrower.			 */						skb->shapepend=0;			shaper_queue_xmit(shaper, skb);	/* Fire */		}		else			break;	}	/*	 *	Next kick.	 */	 	if(skb!=NULL)		mod_timer(&shaper->timer, skb->shapeclock);	clear_bit(0, &shaper->locked);}/* *	Flush the shaper queues on a closedown */ static void shaper_flush(struct shaper *shaper){	struct sk_buff *skb; 	if(!shaper_lock(shaper))	{		printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n"); 		return;	}	while((skb=skb_dequeue(&shaper->sendq))!=NULL)		dev_kfree_skb(skb);	shaper_unlock(shaper);}

⌨️ 快捷键说明

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