--- linux-2.2.17orig/include/linux/skbuff.h Thu May 13 19:33:17 1999 +++ linux-2.2/include/linux/skbuff.h Mon Oct 15 21:03:31 2001 @@ -85,6 +85,9 @@ struct sk_buff { pkt_type, /* Packet class */ pkt_bridged, /* Tracker for bridging */ ip_summed; /* Driver fed us an IP checksum */ +#ifdef CONFIG_IMQ + short from_imq; /* Pkt from IMQ */ +#endif __u32 priority; /* Packet queueing priority */ atomic_t users; /* User count - see datagram.c,tcp.c */ unsigned short protocol; /* Packet protocol from driver. */ --- linux-2.2.17orig/include/linux/netdevice.h Tue Jan 4 19:12:25 2000 +++ linux-2.2/include/linux/netdevice.h Mon Oct 15 21:35:35 2001 @@ -335,6 +335,9 @@ struct packet_type #include extern struct device loopback_dev; /* The loopback */ +#ifdef CONFIG_IMQ +extern struct device imq_dev; /* The IMQ */ +#endif extern struct device *dev_base; /* All devices */ extern struct packet_type *ptype_base[16]; /* Hashed types */ extern int netdev_dropping; --- linux-2.2.17orig/net/core/skbuff.c Sun Mar 7 19:12:18 1999 +++ linux-2.2/net/core/skbuff.c Mon Oct 15 21:06:41 2001 @@ -196,6 +196,9 @@ skb->destructor = NULL; skb->pkt_type = PACKET_HOST; /* Default type */ +#ifdef CONFIG_IMQ + skb->from_imq = 0; +#endif skb->prev = skb->next = NULL; skb->list = NULL; skb->sk = NULL; @@ -312,6 +315,9 @@ n->is_clone=0; atomic_set(&n->users, 1); n->pkt_type=skb->pkt_type; +#ifdef CONFIG_IMQ + n->from_imq=skb->from_imq; +#endif n->stamp=skb->stamp; n->destructor = NULL; n->security=skb->security; @@ -361,6 +367,9 @@ n->is_clone=0; atomic_set(&n->users, 1); n->pkt_type=skb->pkt_type; +#ifdef CONFIG_IMQ + n->from_imq=skb->from_imq; +#endif n->stamp=skb->stamp; n->destructor = NULL; n->security=skb->security; --- linux-2.2.17orig/drivers/net/Config.in Sun Sep 9 22:23:47 2001 +++ linux-2.2/drivers/net/Config.in Mon Oct 15 21:40:48 2001 @@ -21,6 +21,7 @@ tristate 'Dummy net driver support' CONF tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'IMQ (intermediate queue device) support' CONFIG_IMQ if [ "$CONFIG_NETLINK" = "y" ]; then tristate 'Ethertap network tap' CONFIG_ETHERTAP fi --- linux-2.2.17orig/drivers/net/Makefile Sun Sep 9 22:23:47 2001 +++ linux-2.2/drivers/net/Makefile Mon Oct 15 21:41:59 2001 @@ -55,6 +55,10 @@ ifeq ($(CONFIG_NET),y) L_OBJS += Space.o net_init.o loopback.o endif +ifeq ($(CONFIG_IMQ),y) +L_OBJS += imq.o +endif + ifeq ($(CONFIG_SEEQ8005),y) L_OBJS += seeq8005.o endif --- linux-2.2.17orig/Documentation/Configure.help Sun Sep 9 22:23:46 2001 +++ linux-2.2/Documentation/Configure.help Mon Oct 15 22:04:15 2001 @@ -16738,6 +16738,14 @@ If you do not have a CompactPCI model CP1400 or CP1500, or another UltraSPARC-IIi-cEngine boardset with digital display, you should say N to this option. + +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. CP1XXX Hardware Watchdog support CONFIG_WATCHDOG_CP1XXX --- linux-2.2.17orig/drivers/net/Space.c Sun Sep 9 22:23:47 2001 +++ linux-2.2/drivers/net/Space.c Mon Oct 15 22:34:03 2001 @@ -979,6 +979,14 @@ static struct device tr0_dev = { #undef NEXT_DEV #define NEXT_DEV (&escon0_dev) #endif + +#ifdef CONFIG_IMQ + extern int imq_init(struct device *dev); + struct 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 extern int loopback_init(struct device *dev); struct device loopback_dev = { --- linux-2.2.17orig/drivers/net/imq.c Tue Oct 16 12:52:09 2001 +++ linux-2.2/drivers/net/imq.c Mon Oct 15 22:40:46 2001 @@ -0,0 +1,103 @@ +/* + * 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 + +/* + * 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 device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + struct 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->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 device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +/* Initialize the rest of the imq device. */ +__initfunc(int imq_init(struct device *dev)) +{ + dev->hard_start_xmit = imq_xmit; + + dev->type = 0; + 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; + + return(0); +}; --- linux-2.2.17orig/net/core/dev.c Sun Sep 9 22:23:50 2001 +++ linux-2.2/net/core/dev.c Mon Oct 15 22:23:30 2001 @@ -595,6 +595,21 @@ int dev_queue_xmit(struct sk_buff *skb) #endif start_bh_atomic(); +#ifdef CONFIG_IMQ + /* if skb have not visited enabled IMQ yet then push it there */ + q = imq_dev.qdisc; + if (imq_dev.flags&IFF_UP && !skb->from_imq && q->enqueue) { + q->enqueue(skb, q); + qdisc_wakeup(&imq_dev); + end_bh_atomic(); + +#ifdef CONFIG_NET_PROFILE + NET_PROFILE_LEAVE(dev_queue_xmit); + end_bh_atomic(); +#endif + return 0; + } +#endif q = dev->qdisc; if (q->enqueue) { q->enqueue(skb, q); @@ -618,8 +633,11 @@ int dev_queue_xmit(struct sk_buff *skb) made by us here. */ if (dev->flags&IFF_UP) { - 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) { end_bh_atomic(); --- linux-2.2.17orig/net/sched/sch_generic.c Wed Oct 27 02:53:42 1999 +++ linux-2.2/net/sched/sch_generic.c Mon Oct 15 21:29:27 2001 @@ -53,8 +53,11 @@ int qdisc_restart(struct device *dev) struct sk_buff *skb; if ((skb = q->dequeue(q)) != NULL) { - 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) { q->tx_last = jiffies;