diff options
Diffstat (limited to 'drivers/net/shaper.c')
-rw-r--r-- | drivers/net/shaper.c | 603 |
1 files changed, 0 insertions, 603 deletions
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c deleted file mode 100644 index 228f650250f..00000000000 --- a/drivers/net/shaper.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Simple traffic shaper for Linux NET3. - * - * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. - * http://www.redhat.com - * - * 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 - * - * Update History : - * - * 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 - * - * Device statistics (tx_pakets, tx_bytes, - * tx_drops: queue_over_time and collisions: max_queue_exceded) - * 1999/06/18 Jordi Murgo <savage@apostols.org> - * - * Use skb->cb for private data. - * 2000/03 Andi Kleen - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/slab.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 <linux/if_shaper.h> -#include <linux/jiffies.h> - -#include <net/dst.h> -#include <net/arp.h> -#include <net/net_namespace.h> - -struct shaper_cb { - unsigned long shapeclock; /* Time it should go out */ - unsigned long shapestamp; /* Stamp for shaper */ - __u32 shapelatency; /* Latency on frame */ - __u32 shapelen; /* Frame length in clocks */ - __u16 shapepend; /* Pending */ -}; -#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb)) - -static int sh_debug; /* Debug flag */ - -#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" - -static void shaper_kick(struct shaper *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_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct shaper *shaper = dev->priv; - struct sk_buff *ptr; - - spin_lock(&shaper->lock); - ptr=shaper->sendq.prev; - - /* - * Set up our packet details - */ - - SHAPERCB(skb)->shapelatency=0; - SHAPERCB(skb)->shapeclock=shaper->recovery; - if(time_before(SHAPERCB(skb)->shapeclock, jiffies)) - SHAPERCB(skb)->shapeclock=jiffies; - skb->priority=0; /* short term bug fix */ - SHAPERCB(skb)->shapestamp=jiffies; - - /* - * Time slots for this packet. - */ - - SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb); - - { - 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) - SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen; - /* - * Queue over time. Spill packet. - */ - if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - } else - skb_queue_tail(&shaper->sendq, skb); - } - - if(sh_debug) - printk("Frame queued.\n"); - if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) - { - ptr=skb_dequeue(&shaper->sendq); - dev_kfree_skb(ptr); - dev->stats.collisions++; - } - shaper_kick(shaper); - spin_unlock(&shaper->lock); - 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); - - shaper->dev->stats.tx_bytes += skb->len; - shaper->dev->stats.tx_packets++; - - 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 *shaper = (struct shaper *)data; - - spin_lock(&shaper->lock); - shaper_kick(shaper); - spin_unlock(&shaper->lock); -} - -/* - * Kick a shaper queue and try and do something sensible with the - * queue. - */ - -static void shaper_kick(struct shaper *shaper) -{ - struct sk_buff *skb; - - /* - * 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 = %ld, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies); - if(time_before_eq(SHAPERCB(skb)->shapeclock, jiffies + SHAPER_BURST)) - { - /* - * Pull the frame and get interrupts back on. - */ - - skb_unlink(skb, &shaper->sendq); - if (shaper->recovery < - SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen) - shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen; - /* - * Pass on to the physical target device via - * our low level packet thrower. - */ - - SHAPERCB(skb)->shapepend=0; - shaper_queue_xmit(shaper, skb); /* Fire */ - } - else - break; - } - - /* - * Next kick. - */ - - if(skb!=NULL) - mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); -} - - -/* - * Bring the interface up. We just disallow this until a - * bind. - */ - -static int shaper_open(struct net_device *dev) -{ - struct shaper *shaper=dev->priv; - - /* - * Can't open until attached. - * Also can't open until speed is set, or we'll get - * a division by zero. - */ - - if(shaper->dev==NULL) - return -ENODEV; - if(shaper->bitspersec==0) - return -EINVAL; - return 0; -} - -/* - * Closing a shaper flushes the queues. - */ - -static int shaper_close(struct net_device *dev) -{ - struct shaper *shaper=dev->priv; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&shaper->sendq)) != NULL) - dev_kfree_skb(skb); - - spin_lock_bh(&shaper->lock); - shaper_kick(shaper); - spin_unlock_bh(&shaper->lock); - - del_timer_sync(&shaper->timer); - return 0; -} - -/* - * Revectored calls. We alter the parameters and call the functions - * for our attached device. This enables us to bandwidth allocate after - * ARP and other resolutions and not before. - */ - -static int shaper_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned len) -{ - struct shaper *sh=dev->priv; - int v; - if(sh_debug) - printk("Shaper header\n"); - skb->dev = sh->dev; - v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len); - skb->dev = dev; - return v; -} - -static int shaper_rebuild_header(struct sk_buff *skb) -{ - struct shaper *sh=skb->dev->priv; - struct net_device *dev=skb->dev; - int v; - if(sh_debug) - printk("Shaper rebuild header\n"); - skb->dev=sh->dev; - v = sh->dev->header_ops->rebuild(skb); - skb->dev=dev; - return v; -} - -#if 0 -static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh) -{ - struct shaper *sh=neigh->dev->priv; - struct net_device *tmp; - int ret; - if(sh_debug) - printk("Shaper header cache bind\n"); - tmp=neigh->dev; - neigh->dev=sh->dev; - ret=sh->hard_header_cache(neigh,hh); - neigh->dev=tmp; - return ret; -} - -static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char *haddr) -{ - struct shaper *sh=dev->priv; - if(sh_debug) - printk("Shaper cache update\n"); - sh->header_cache_update(hh, sh->dev, haddr); -} -#endif - -#ifdef CONFIG_INET - -static int shaper_neigh_setup(struct neighbour *n) -{ -#ifdef CONFIG_INET - if (n->nud_state == NUD_NONE) { - n->ops = &arp_broken_ops; - n->output = n->ops->output; - } -#endif - return 0; -} - -static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ -#ifdef CONFIG_INET - if (p->tbl->family == AF_INET) { - p->neigh_setup = shaper_neigh_setup; - p->ucast_probes = 0; - p->mcast_probes = 0; - } -#endif - return 0; -} - -#else /* !(CONFIG_INET) */ - -static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ - return 0; -} - -#endif - -static const struct header_ops shaper_ops = { - .create = shaper_header, - .rebuild = shaper_rebuild_header, -}; - -static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev) -{ - sh->dev = dev; - sh->get_stats=dev->get_stats; - - shdev->neigh_setup = shaper_neigh_setup_dev; - shdev->hard_header_len=dev->hard_header_len; - shdev->type=dev->type; - shdev->addr_len=dev->addr_len; - shdev->mtu=dev->mtu; - sh->bitspersec=0; - return 0; -} - -static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru; - struct shaper *sh=dev->priv; - - if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED) - { - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - switch(ss->ss_cmd) - { - case SHAPER_SET_DEV: - { - struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name); - if(them==NULL) - return -ENODEV; - if(sh->dev) - return -EBUSY; - return shaper_attach(dev,dev->priv, them); - } - case SHAPER_GET_DEV: - if(sh->dev==NULL) - return -ENODEV; - strcpy(ss->ss_name, sh->dev->name); - return 0; - case SHAPER_SET_SPEED: - shaper_setspeed(sh,ss->ss_speed); - return 0; - case SHAPER_GET_SPEED: - ss->ss_speed=sh->bitspersec; - return 0; - default: - return -EINVAL; - } -} - -static void shaper_init_priv(struct net_device *dev) -{ - struct shaper *sh = dev->priv; - - skb_queue_head_init(&sh->sendq); - init_timer(&sh->timer); - sh->timer.function=shaper_timer; - sh->timer.data=(unsigned long)sh; - spin_lock_init(&sh->lock); -} - -/* - * Add a shaper device to the system - */ - -static void __init shaper_setup(struct net_device *dev) -{ - /* - * Set up the shaper. - */ - - shaper_init_priv(dev); - - dev->open = shaper_open; - dev->stop = shaper_close; - dev->hard_start_xmit = shaper_start_xmit; - dev->set_multicast_list = NULL; - - /* - * Intialise the packet queues - */ - - /* - * Handlers for when we attach to a device. - */ - - dev->neigh_setup = shaper_neigh_setup_dev; - dev->do_ioctl = shaper_ioctl; - dev->hard_header_len = 0; - dev->type = ARPHRD_ETHER; /* initially */ - dev->set_mac_address = NULL; - dev->mtu = 1500; - dev->addr_len = 0; - dev->tx_queue_len = 10; - dev->flags = 0; -} - -static int shapers = 1; -#ifdef MODULE - -module_param(shapers, int, 0); -MODULE_PARM_DESC(shapers, "Traffic shaper: maximum number of shapers"); - -#else /* MODULE */ - -static int __init set_num_shapers(char *str) -{ - shapers = simple_strtol(str, NULL, 0); - return 1; -} - -__setup("shapers=", set_num_shapers); - -#endif /* MODULE */ - -static struct net_device **devs; - -static unsigned int shapers_registered = 0; - -static int __init shaper_init(void) -{ - int i; - size_t alloc_size; - struct net_device *dev; - char name[IFNAMSIZ]; - - if (shapers < 1) - return -ENODEV; - - alloc_size = sizeof(*dev) * shapers; - devs = kzalloc(alloc_size, GFP_KERNEL); - if (!devs) - return -ENOMEM; - - for (i = 0; i < shapers; i++) { - - snprintf(name, IFNAMSIZ, "shaper%d", i); - dev = alloc_netdev(sizeof(struct shaper), name, - shaper_setup); - if (!dev) - break; - - if (register_netdev(dev)) { - free_netdev(dev); - break; - } - - devs[i] = dev; - shapers_registered++; - } - - if (!shapers_registered) { - kfree(devs); - devs = NULL; - } - - return (shapers_registered ? 0 : -ENODEV); -} - -static void __exit shaper_exit (void) -{ - int i; - - for (i = 0; i < shapers_registered; i++) { - if (devs[i]) { - unregister_netdev(devs[i]); - free_netdev(devs[i]); - } - } - - kfree(devs); - devs = NULL; -} - -module_init(shaper_init); -module_exit(shaper_exit); -MODULE_LICENSE("GPL"); - |