Dave,
This is intended for 2.6.16 since it is a new feature.

To everyone who has contacted me over the last few months, I apologize
for sitting on this for so long (Ive tried to CC a few). I tend to have
more time at year end - and so here it is. This patch does not support
feature #3 in the thread of discussion at:
http://marc.theaimsgroup.com/?t=110712330700001&r=2&w=2
The reason infact i was sitting on it is to try and get #3 out first.
That could come later;

while this is for 2.6.16 it should apply cleanly to any
of the 2.6.15-rcx trees (infact thats where i tested it). I am going to
send an iproute2 patch that is only documentation on usage etc.

cheers,
jamal
Extends dummy to do IMQ functions with a lot less lines and
a lot more stability.
Old uses of dummy such as for dial-on-demand continue to work as
before.
To use the new functionality, you need to turn on qos/classifier actions.
The new functionality can be grouped as:
1) qdiscs/policies that are per device as opposed to system wide.
This now allows for sharing.

2) Allows for queueing incoming traffic for shaping instead of
dropping. I am not aware of any study that shows policing is
worse than shaping in achieving the end goal of rate control.
I would be interested if anyone is experimenting.

Signed-off-by: Jamal Hadi Salim <[EMAIL PROTECTED]>
---

 drivers/net/dummy.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 215 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index dd8c15a..6c2a0bf 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -26,8 +26,15 @@
                        Nick Holloway, 27th May 1994
        [I tweaked this explanation a little but that's all]
                        Alan Cox, 30th May 1994
+
+*/
+/*
+       * This driver isnt abused enough ;->
+       * Here to add only _just_ a _feeew more_ features,
+       * 10 years after AC added comment above ;-> hehe - JHS
 */
 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -35,11 +42,130 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
+#ifdef CONFIG_NET_CLS_ACT
+#include <net/pkt_sched.h> 
+#endif
+
+#define TX_TIMEOUT  (2*HZ)
+                                                                               
 
+#define TX_Q_LIMIT    32
+struct dummy_private {
+       struct net_device_stats stats;
+#ifdef CONFIG_NET_CLS_ACT
+       struct tasklet_struct   dummy_tasklet;
+       int     tasklet_pending;
+       /* mostly debug stats leave in for now */
+       unsigned long   stat_te; /* tasklet entered */
+       unsigned long   stat_tqr; /* transmit queue refill attempt */
+       unsigned long   stat_rqe; /* receive queue entered */
+       unsigned long   stat_r2t; /* receive to trasmit transfers */
+       unsigned long   stat_rqne; /*receiveQ not entered, tasklet resched */
+       unsigned long   stat_rfe; /* received from egress path */
+       unsigned long   stat_rfi; /* received from ingress path */
+       unsigned long   stat_crq;
+       unsigned long   stat_rqw;
+       struct sk_buff_head     rq;
+       struct sk_buff_head     tq;
+#endif
+};
+
+#ifdef CONFIG_NET_CLS_ACT
+static void ri_tasklet(unsigned long dev);
+#endif
+
 
 static int numdummies = 1;
 
 static int dummy_xmit(struct sk_buff *skb, struct net_device *dev);
 static struct net_device_stats *dummy_get_stats(struct net_device *dev);
+static void dummy_timeout(struct net_device *dev);
+static int dummy_open(struct net_device *dev);
+static int dummy_close(struct net_device *dev);
+
+static void dummy_timeout(struct net_device *dev) {
+
+       int cpu = smp_processor_id();
+
+       dev->trans_start = jiffies;
+       printk("%s: BUG tx timeout on CPU %d\n",dev->name,cpu);
+       if (spin_is_locked((&dev->xmit_lock)))
+               printk("xmit lock grabbed already\n");
+       if (spin_is_locked((&dev->queue_lock)))
+               printk("queue lock grabbed already\n");
+}
+
+#ifdef CONFIG_NET_CLS_ACT
+static void ri_tasklet(unsigned long dev) {
+
+       struct net_device *dv = (struct net_device *)dev;
+       struct dummy_private *dp = ((struct net_device *)dev)->priv;
+       struct net_device_stats *stats = &dp->stats;
+       struct sk_buff *skb = NULL;
+
+       dp->stat_te +=1;
+       if (NULL == (skb = skb_peek(&dp->tq))) {
+               dp->stat_tqr +=1;
+               if (spin_trylock(&dv->xmit_lock)) {
+                       dp->stat_rqe +=1;
+                       while (NULL != (skb = skb_dequeue(&dp->rq))) {
+                               skb_queue_tail(&dp->tq, skb);
+                               dp->stat_r2t +=1;
+                       }
+                       spin_unlock(&dv->xmit_lock);
+               } else {
+                       /* reschedule */
+                       dp->stat_rqne +=1;
+                       goto resched;
+               }
+       }
+
+       while (NULL != (skb = skb_dequeue(&dp->tq))) {
+               __u32 from = G_TC_FROM(skb->tc_verd);
+
+               skb->tc_verd = 0;
+               skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
+               stats->tx_packets++;
+               stats->tx_bytes +=skb->len;
+               if (from & AT_EGRESS) {
+                       dp->stat_rfe +=1;
+                       dev_queue_xmit(skb);
+               } else if (from & AT_INGRESS) {
+
+                       dp->stat_rfi +=1;
+                       netif_rx(skb);
+               } else {
+                       /* if netfilt is compiled in and packet is
+                       tagged, we could reinject the packet back
+                       this would make it do remaining 10%
+                       of what current IMQ does  
+                       if someone really really insists then
+                       this is the spot .. jhs */
+                       dev_kfree_skb(skb);
+                       stats->tx_dropped++;
+               }
+       }
+
+       if (spin_trylock(&dv->xmit_lock)) {
+               dp->stat_crq +=1;
+               if (NULL == (skb = skb_peek(&dp->rq))) {
+                       dp->tasklet_pending = 0;
+                       if (netif_queue_stopped(dv))
+                               netif_wake_queue(dv);
+                               //netif_start_queue(dv);
+               } else {
+                       dp->stat_rqw +=1;
+                       spin_unlock(&dv->xmit_lock);
+                       goto resched;
+               }
+               spin_unlock(&dv->xmit_lock);
+       } else {
+resched:
+               dp->tasklet_pending = 1;
+               tasklet_schedule(&dp->dummy_tasklet);
+       }
+
+}
+#endif
 
 static int dummy_set_address(struct net_device *dev, void *p)
 {
@@ -62,12 +188,17 @@ static void __init dummy_setup(struct ne
        /* Initialize the device structure. */
        dev->get_stats = dummy_get_stats;
        dev->hard_start_xmit = dummy_xmit;
+       dev->tx_timeout = &dummy_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       dev->open = &dummy_open;
+       dev->stop = &dummy_close;
+
        dev->set_multicast_list = set_multicast_list;
        dev->set_mac_address = dummy_set_address;
 
        /* Fill in device structure with ethernet-generic values. */
        ether_setup(dev);
-       dev->tx_queue_len = 0;
+       dev->tx_queue_len = TX_Q_LIMIT;
        dev->change_mtu = NULL;
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
@@ -77,18 +208,64 @@ static void __init dummy_setup(struct ne
 
 static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct net_device_stats *stats = netdev_priv(dev);
+       struct dummy_private *dp = ((struct net_device *)dev)->priv;
+       struct net_device_stats *stats = &dp->stats;
+       int ret = 0;
 
+       {
        stats->tx_packets++;
        stats->tx_bytes+=skb->len;
+       }
+#ifdef CONFIG_NET_CLS_ACT
+       __u32 from = G_TC_FROM(skb->tc_verd);
+       if (!from || !skb->input_dev ) {
+dropped:
+                dev_kfree_skb(skb);
+                stats->rx_dropped++;
+                return ret;
+       } else {
+               if (skb->input_dev)
+                       skb->dev = skb->input_dev;
+               else
+                       printk("warning!!! no idev %s\n",skb->dev->name);
+
+               skb->input_dev = dev;
+               if (from & AT_INGRESS) {
+                       skb_pull(skb, skb->dev->hard_header_len);
+               } else {
+                       if (!(from & AT_EGRESS)) {
+                               goto dropped;
+                       }
+               }
+       }
+       if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) {
+               netif_stop_queue(dev);
+       }
+       dev->trans_start = jiffies;
+       skb_queue_tail(&dp->rq, skb);
+       if (!dp->tasklet_pending) {
+               dp->tasklet_pending = 1;
+               tasklet_schedule(&dp->dummy_tasklet);
+       }
 
+#else
+       stats->rx_dropped++;
        dev_kfree_skb(skb);
-       return 0;
+#endif
+       return ret;
 }
 
 static struct net_device_stats *dummy_get_stats(struct net_device *dev)
 {
-       return netdev_priv(dev);
+       struct dummy_private *dp = ((struct net_device *)dev)->priv;
+       struct net_device_stats *stats = &dp->stats;
+
+       pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
+               dp->stat_rqne, dp->stat_rqw, dp->stat_crq,
+               dp->stat_te, dp->stat_tqr, dp->stat_rfe,
+               dp->stat_rfi,dp->stat_rqe, dp->stat_r2t);
+
+       return stats;
 }
 
 static struct net_device **dummies;
@@ -97,12 +274,42 @@ static struct net_device **dummies;
 module_param(numdummies, int, 0);
 MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
 
+static int dummy_close(struct net_device *dev)
+{
+
+#ifdef CONFIG_NET_CLS_ACT
+       struct dummy_private *dp = ((struct net_device *)dev)->priv;
+
+       tasklet_kill(&dp->dummy_tasklet);
+       skb_queue_purge(&dp->rq);
+       skb_queue_purge(&dp->tq);
+#endif
+       netif_stop_queue(dev);
+       return 0;
+}
+
+static int dummy_open(struct net_device *dev)
+{
+
+#ifdef CONFIG_NET_CLS_ACT
+       struct dummy_private *dp = ((struct net_device *)dev)->priv;
+
+       tasklet_init(&dp->dummy_tasklet, ri_tasklet, (unsigned long)dev);
+       skb_queue_head_init(&dp->rq);
+       skb_queue_head_init(&dp->tq);
+#endif
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+
 static int __init dummy_init_one(int index)
 {
        struct net_device *dev_dummy;
        int err;
 
-       dev_dummy = alloc_netdev(sizeof(struct net_device_stats),
+       dev_dummy = alloc_netdev(sizeof(struct dummy_private),
                                 "dummy%d", dummy_setup);
 
        if (!dev_dummy)
@@ -128,6 +335,7 @@ static int __init dummy_init_module(void
 { 
        int i, err = 0;
        dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL); 
+
        if (!dummies)
                return -ENOMEM; 
        for (i = 0; i < numdummies && !err; i++)
@@ -136,12 +344,14 @@ static int __init dummy_init_module(void
                while (--i >= 0)
                        dummy_free_one(i);
        }
+
        return err;
 } 
 
 static void __exit dummy_cleanup_module(void)
 {
        int i;
+
        for (i = 0; i < numdummies; i++) 
                dummy_free_one(i); 
        kfree(dummies); 

Reply via email to