While I have nothing against the idea, the patch needs a lot
of cleanup. You seem to add almost as much ifdefed code to
dummy as it currently has, which makes me wonder if a completely
new device wouldn't be much cleaner.
jamal wrote:
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
*/
+
Useless newline
#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
Just include in unconditionally instead of adding ugly ifdefs.
+
+#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;
I would prefer more descriptive names, like tasklet_entered,
txqueue_refill_attempt, ...
I also don't see a way to actually read these stats, except by
enabling debugging.
+ struct sk_buff_head rq;
+ struct sk_buff_head tq;
+#endif
+};
+
+#ifdef CONFIG_NET_CLS_ACT
+static void ri_tasklet(unsigned long dev);
+#endif
Please avoid the excessive use of ifdefs. Unused forward-declarations
don't hurt. It seems to be unnecessary anyway.
+
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) {
opening parenthesis of a function body go on a new line.
+
+ 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");
+}
The watchdog always takes xmit_lock, and these "... lock grabbed
already" printks look totally useless.
+
+#ifdef CONFIG_NET_CLS_ACT
+static void ri_tasklet(unsigned long dev) {
+
+ struct net_device *dv = (struct net_device *)dev;
dev is a much nicer name than dv, please use __dev or something
for the unsigned long and dev for the struct netdevice *.
+ struct dummy_private *dp = ((struct net_device *)dev)->priv;
dummy currently uses netdev_priv(), please don't change that without
a reason.
+ struct net_device_stats *stats = &dp->stats;
+ struct sk_buff *skb = NULL;
No need to initialize to NULL, it is assigned a value right below.
+
+ dp->stat_te +=1;
+=<space>1, below you use ++ half of the time.
+ if (NULL == (skb = skb_peek(&dp->tq))) {
Please avoid these backward comparisions, especially if the
remaining file already does it the other way around.
+ 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);
Looks like you want skb_move or something like that. Why do
you need this shoving skbs between queues anyway? You pull
them out of the queue again right below.
+ 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);
u32
+
+ 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++;
Packets that are queued from netfilter must not be freed other
than by passing them to nf_reinject with a verdict of drop.
It doesn't look as if you were using netfilter at all, but
at least that comment is wrong.
+ }
+ }
+
+ 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);
u32
+ if (!from || !skb->input_dev ) {
unnecessary space before closing bracket
+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;
Is that still necessary and/or correct? We moved the input_dev
assignment to netif_receive_skb().
+ 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)
+{
+
Please kill the above newline
+#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)
+{
+
this one too
+#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;
+}
+
+
this one too
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);
+
unrelated newline-change, more below.
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);
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html