#include <linux/config.h>
#include <linux/module.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
{
struct netem_sched_data *q = qdisc_priv(sch);
struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
+ psched_tdiff_t td;
psched_time_t now;
PSCHED_GET_TIME(now);
- PSCHED_TADD2(now, tabledist(q->latency, q->jitter,
- &q->delay_cor, q->delay_dist),
- cb->time_to_send);
+ td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist);
+ PSCHED_TADD2(now, td, cb->time_to_send);
/* Always queue at tail to keep packets in order */
if (likely(q->delayed.qlen < q->limit)) {
__skb_queue_tail(&q->delayed, skb);
- sch->q.qlen++;
- sch->stats.bytes += skb->len;
- sch->stats.packets++;
+ sch->bstats.bytes += skb->len;
+ sch->bstats.packets++;
+
+ if (!timer_pending(&q->timer)) {
+ q->timer.expires = jiffies + PSCHED_US2JIFFIE(td);
+ add_timer(&q->timer);
+ }
return NET_XMIT_SUCCESS;
}
- sch->stats.drops++;
+ sch->qstats.drops++;
kfree_skb(skb);
return NET_XMIT_DROP;
}
/* Random packet drop 0 => none, ~0 => all */
if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
pr_debug("netem_enqueue: random loss\n");
- sch->stats.drops++;
+ sch->qstats.drops++;
+ kfree_skb(skb);
return 0; /* lie about loss so TCP doesn't know */
}
++q->counter;
ret = q->qdisc->enqueue(skb, q->qdisc);
- if (ret)
- sch->stats.drops++;
+ if (likely(ret == NET_XMIT_SUCCESS)) {
+ sch->q.qlen++;
+ sch->bstats.bytes += skb->len;
+ sch->bstats.packets++;
+ } else
+ sch->qstats.drops++;
return ret;
}
struct netem_sched_data *q = qdisc_priv(sch);
int ret;
- if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0)
+ if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
sch->q.qlen++;
+ sch->qstats.requeues++;
+ }
return ret;
}
if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
sch->q.qlen--;
- sch->stats.drops++;
+ sch->qstats.drops++;
}
return len;
}
{
struct netem_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
+
+ skb = q->qdisc->dequeue(q->qdisc);
+ if (skb)
+ sch->q.qlen--;
+ return skb;
+}
+
+static void netem_watchdog(unsigned long arg)
+{
+ struct Qdisc *sch = (struct Qdisc *)arg;
+ struct netem_sched_data *q = qdisc_priv(sch);
+ struct net_device *dev = sch->dev;
+ struct sk_buff *skb;
psched_time_t now;
+ pr_debug("netem_watchdog: fired @%lu\n", jiffies);
+
+ spin_lock_bh(&dev->queue_lock);
PSCHED_GET_TIME(now);
+
while ((skb = skb_peek(&q->delayed)) != NULL) {
const struct netem_skb_cb *cb
= (const struct netem_skb_cb *)skb->cb;
long delay
= PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
- pr_debug("netem_dequeue: delay queue %p@%lu %ld\n",
+ pr_debug("netem_watchdog: skb %p@%lu %ld\n",
skb, jiffies, delay);
/* if more time remaining? */
__skb_unlink(skb, &q->delayed);
if (q->qdisc->enqueue(skb, q->qdisc))
- sch->stats.drops++;
+ sch->qstats.drops++;
+ else
+ sch->q.qlen++;
}
-
- skb = q->qdisc->dequeue(q->qdisc);
- if (skb)
- sch->q.qlen--;
- return skb;
-}
-
-static void netem_watchdog(unsigned long arg)
-{
- struct Qdisc *sch = (struct Qdisc *)arg;
-
- pr_debug("netem_watchdog: fired @%lu\n", jiffies);
- netif_schedule(sch->dev);
+ qdisc_run(dev);
+ spin_unlock_bh(&dev->queue_lock);
}
static void netem_reset(struct Qdisc *sch)