--- linux-2.4orig/include/linux/skbuff.h Mon Oct 15 16:31:19 2001 +++ linux-2.4/include/linux/skbuff.h Fri Oct 19 00:52:13 2001 @@ -176,7 +176,7 @@ struct sk_buff { unsigned int len; /* Length of actual data */ unsigned int data_len; unsigned int csum; /* Checksum */ - unsigned char __unused, /* Dead field, may be reused */ + unsigned char from_imq, /* read from imq - dont requeue to imq */ cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ --- linux-2.4orig/include/linux/netdevice.h Mon Oct 15 16:33:39 2001 +++ linux-2.4/include/linux/netdevice.h Mon Oct 22 00:28:57 2001 @@ -425,6 +425,9 @@ struct packet_type #include extern struct net_device loopback_dev; /* The loopback */ +#ifdef CONFIG_IMQ +extern struct net_device imq_dev; +#endif extern struct net_device *dev_base; /* All devices */ extern rwlock_t dev_base_lock; /* Device list lock */ --- linux-2.4orig/net/core/skbuff.c Mon Oct 15 16:28:35 2001 +++ linux-2.4/net/core/skbuff.c Mon Oct 15 09:45:07 2001 @@ -203,6 +203,7 @@ struct sk_buff *alloc_skb(unsigned int s /* Set up other state */ skb->len = 0; skb->cloned = 0; + skb->from_imq = 0; skb->data_len = 0; atomic_set(&skb->users, 1); @@ -235,6 +236,7 @@ static inline void skb_headerinit(void * skb->dst = NULL; memset(skb->cb, 0, sizeof(skb->cb)); skb->pkt_type = PACKET_HOST; /* Default type */ + skb->from_imq = 0; skb->ip_summed = 0; skb->priority = 0; skb->security = 0; /* By default packets are insecure */ @@ -373,6 +375,7 @@ struct sk_buff *skb_clone(struct sk_buff C(data_len); C(csum); n->cloned = 1; + C(from_imq); C(pkt_type); C(ip_summed); C(priority); @@ -427,6 +430,7 @@ static void copy_skb_header(struct sk_bu memcpy(new->cb, old->cb, sizeof(old->cb)); atomic_set(&new->users, 1); new->pkt_type=old->pkt_type; + new->from_imq=old->from_imq; new->stamp=old->stamp; new->destructor = NULL; new->security=old->security; --- linux-2.4orig/drivers/net/Config.in Mon Oct 15 16:30:12 2001 +++ linux-2.4/drivers/net/Config.in Mon Oct 22 00:39:51 2001 @@ -7,6 +7,7 @@ source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING +bool 'Intermediate queue (IMQ) driver support' CONFIG_IMQ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then --- linux-2.4orig/drivers/net/Makefile Mon Oct 15 16:30:12 2001 +++ linux-2.4/drivers/net/Makefile Mon Oct 22 00:30:07 2001 @@ -104,6 +104,7 @@ obj-$(CONFIG_WINBOND_840) += winbond-840 obj-$(CONFIG_SUNDANCE) += sundance.o obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o +obj-$(CONFIG_IMQ) += imq.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_NET_SB1000) += sb1000.o --- linux-2.4orig/Documentation/Configure.help Mon Oct 15 16:31:35 2001 +++ linux-2.4/Documentation/Configure.help Mon Oct 22 00:40:49 2001 @@ -7116,6 +7116,14 @@ CONFIG_BONDING say M here and read Documentation/modules.txt. The module will be called bonding.o. +Intermediate queue device (IMQ) +CONFIG_IMQ + This is virtual network device which is mainly used as placeholder + for QoS qdisc. The attached qdisc is enqueued with all packets + before they go to their 'home' qdisc. + It enables qdisc to treat network devices as classes and distribute + bandwidth among them. + SLIP (serial line) support CONFIG_SLIP Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to --- linux-2.4orig/drivers/net/Space.c Mon Oct 15 16:30:12 2001 +++ linux-2.4/drivers/net/Space.c Mon Oct 22 00:31:22 2001 @@ -632,6 +632,14 @@ static struct net_device tr0_dev = { #define NEXT_DEV (&sbni0_dev) #endif +#ifdef CONFIG_IMQ +extern int imq_init(struct net_device *dev); +struct net_device imq_dev = + {"imq", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, imq_init}; +#undef NEXT_DEV +#define NEXT_DEV (&imq_dev) +#endif + /* * The loopback device is global so it can be directly referenced * by the network code. Also, it must be first on device list. --- linux-2.4orig/drivers/net/imq.c Mon Oct 22 00:26:16 2001 +++ linux-2.4/drivers/net/imq.c Mon Oct 15 10:15:41 2001 @@ -0,0 +1,114 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Pseudo-driver for the intermediate queue interface. + * + * Authors: Martin Devera, + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ + +/* + * The higher levels take care of making this non-reentrant (it's + * called with bh's disabled). + */ +static int imq_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + struct net_device *sdev = skb->dev; + + /* + * Optimise so buffers with skb->free=1 are not copied but + * instead are lobbed from tx queue to rx queue + */ + + if(atomic_read(&skb->users) != 1) + { + struct sk_buff *skb2=skb; + skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ + if(skb==NULL) { + kfree_skb(skb2); + return 0; + } + kfree_skb(skb2); + } + else + skb_orphan(skb); + + if (dev == sdev || skb->from_imq) { + if (net_ratelimit()) printk (KERN_ERR "imq device is looped !"); + kfree_skb(skb); + return 0; + } + + /* move the packet into correct device queue */ +// skb->protocol=eth_type_trans(skb,dev); + skb->dev = sdev; + skb->from_imq = 1; + if (dev_queue_xmit(skb) < 0 && net_ratelimit()) + printk (KERN_ERR "Can't TX from imq device\n"); + + dev->last_rx = jiffies; + stats->rx_bytes+=skb->len; + stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->tx_packets++; + + return(0); +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +/* Initialize the rest of the imq device. */ +int __init imq_init(struct net_device *dev) +{ + dev->hard_start_xmit = imq_xmit; + + dev->type = ARPHRD_VOID; + dev->mtu = 1500; + dev->tx_queue_len = 100; + dev->flags = IFF_NOARP; + dev->hard_header_len = LL_MAX_HEADER; + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_device_stats)); + dev->get_stats = get_stats; + + /* + * Fill in the generic fields of the device structure. + */ + + return(0); +}; --- linux-2.4orig/net/core/dev.c Mon Oct 15 16:33:13 2001 +++ linux-2.4/net/core/dev.c Mon Oct 22 00:47:05 2001 @@ -997,6 +1002,22 @@ int dev_queue_xmit(struct sk_buff *skb) return -ENOMEM; } +#ifdef CONFIG_IMQ + /* special intermediate queue up ? */ + if (imq_dev.flags&IFF_UP && !skb->from_imq) { + spin_lock_bh(&imq_dev.queue_lock); + q = imq_dev.qdisc; + if (q->enqueue) { + int ret = q->enqueue(skb, q); + + qdisc_run(&imq_dev); + spin_unlock_bh(&imq_dev.queue_lock); + return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret; + } + spin_unlock_bh(&imq_dev.queue_lock); + } +#endif + /* Grab device queue */ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; @@ -1029,12 +1050,16 @@ int dev_queue_xmit(struct sk_buff *skb) dev->xmit_lock_owner = cpu; if (!netif_queue_stopped(dev)) { - if (netdev_nit) - dev_queue_xmit_nit(skb,dev); + if (netdev_nit +#ifdef CONFIG_IMQ + && !skb->from_imq +#endif + ) dev_queue_xmit_nit(skb,dev); if (dev->hard_start_xmit(skb, dev) == 0) { dev->xmit_lock_owner = -1; spin_unlock_bh(&dev->xmit_lock); + NET_PROFILE_LEAVE(dev_queue_xmit); return 0; } } --- linux-2.4orig/net/sched/sch_generic.c Sat Jan 27 11:11:47 2001 +++ linux-2.4/net/sched/sch_generic.c Mon Oct 22 00:37:52 2001 @@ -89,8 +88,12 @@ int qdisc_restart(struct net_device *dev spin_unlock(&dev->queue_lock); if (!netif_queue_stopped(dev)) { - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); + /* don't nit intermediate packet here */ + if (netdev_nit +#ifdef CONFIG_IMQ + && !skb->from_imq +#endif + ) dev_queue_xmit_nit(skb, dev); if (dev->hard_start_xmit(skb, dev) == 0) { dev->xmit_lock_owner = -1;