netdev
[Top] [All Lists]

[PATCH] Add selective delay to sch_dealy (aka sch_ooo)

To: "David S. Miller" <davem@xxxxxxxxxx>
Subject: [PATCH] Add selective delay to sch_dealy (aka sch_ooo)
From: Catalin BOIE <util@xxxxxxxxxxxxxxx>
Date: Mon, 28 Jun 2004 16:25:59 +0300 (EEST)
Cc: linux-kernel@xxxxxxxxxxxxxxx, netdev@xxxxxxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
Hello!

David, please apply.
I tested it and works as expected.
Seems Stephen doesn't have time to look over.
Thank you very much.

Signed-off-by: Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>

--- linux-2.6.7-bk5.orig/net/sched/sch_delay.c 2004-06-23 12:18:00.000000000 +0300 +++ linux-2.6.7-bk5/net/sched/sch_delay.c 2004-06-24 10:41:02.000000000 +0300
@@ -7,6 +7,7 @@
  *             2 of the License, or (at your option) any later version.
  *
  * Authors:    Stephen Hemminger <shemminger@xxxxxxxx>
+               Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
  */

 #include <linux/config.h>
@@ -33,7 +34,7 @@
 #include <net/pkt_sched.h>

 /*     Network delay simulator
-       This scheduler adds a fixed delay to all packets.
+       This scheduler adds a fixed delay to all/some packets.
        Similar to NISTnet and BSD Dummynet.

        It uses byte fifo underneath similar to TBF */
@@ -41,8 +42,12 @@ struct dly_sched_data {
        u32     latency;
        u32     limit;
        u32     loss;
+       u32     gap;    /* gap between packets: 0=all pkts are processed */
        struct timer_list timer;
        struct Qdisc *qdisc;
+       struct sk_buff_head qooo;
+       u32     send_from_qooo;
+       u32     counter;
 };

 /* Time stamp put into socket buffer control block */
@@ -59,6 +64,8 @@ static int dly_enqueue(struct sk_buff *s
        struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb;
        int ret;

+       pr_debug("enqueue:\n");
+
        /* Random packet drop 0 => none, ~0 => all */
        if (q->loss >= net_random()) {
                sch->stats.drops++;
@@ -104,6 +111,26 @@ static unsigned int dly_drop(struct Qdis
        return len;
 }

+static void dly_mod_timer(struct dly_sched_data *q, struct sk_buff *skb)
+{
+       struct dly_skb_cb       *cb;
+       psched_time_t           now;
+       long                    diff, delay;
+
+       if (timer_pending(&q->timer))
+               return;
+
+       cb = (struct dly_skb_cb *)skb->cb;
+       PSCHED_GET_TIME(now);
+       diff = q->latency - PSCHED_TDIFF(now, cb->queuetime);
+       delay = PSCHED_US2JIFFIE(diff);
+       if (delay <= 0)
+               delay = 1;
+       mod_timer(&q->timer, jiffies + delay);
+
+       pr_debug("mod_timer: Set new timer to %ld\n", jiffies + delay);
+}
+
 /* Dequeue packet.
  * If packet needs to be held up, then stop the
  * queue and set timer to wakeup later.
@@ -111,37 +138,54 @@ static unsigned int dly_drop(struct Qdis
 static struct sk_buff *dly_dequeue(struct Qdisc *sch)
 {
        struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *skb2;

- retry:
-       skb = q->qdisc->dequeue(q->qdisc);
-       if (skb) {
-               struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb;
-               psched_time_t now;
-               long diff, delay;
-
-               PSCHED_GET_TIME(now);
-               diff = q->latency - PSCHED_TDIFF(now, cb->queuetime);
-
-               if (diff <= 0) {
-                       sch->q.qlen--;
-                       sch->flags &= ~TCQ_F_THROTTLED;
-                       return skb;
+       /* test if we must dequeue from qooo */
+       if (q->send_from_qooo == 1) {
+               q->send_from_qooo = 0;
+
+               skb = __skb_dequeue(&q->qooo);
+               if (skb == NULL) {
+ pr_debug("dequeue: BUG! send_from_qooo == 1 and queue empty!\n");
+                       return NULL;
                }

- if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
-                       sch->q.qlen--;
-                       sch->stats.drops++;
-                       goto retry;
+               pr_debug("dequeue: from qooo queue [%p]\n", skb);
+               sch->q.qlen--;
+
+               /* set timer to next event */
+               skb2 = __skb_dequeue(&q->qooo);
+               if (skb2) {
+                       dly_mod_timer(q, skb2);
+                       __skb_queue_head(&q->qooo, skb2);
                }

-               delay = PSCHED_US2JIFFIE(diff);
-               if (delay <= 0)
-                 delay = 1;
-               mod_timer(&q->timer, jiffies+delay);
+               return skb;
+       }
+
+       skb = q->qdisc->dequeue(q->qdisc);
+       if (skb == NULL)
+               return NULL;
+
+       if (q->counter < q->gap) {
+               pr_debug("dequeue: don't touch this packet\n");
+               q->counter++;

-               sch->flags |= TCQ_F_THROTTLED;
+               sch->q.qlen--;
+               sch->flags &= ~TCQ_F_THROTTLED;
+               return skb;
        }
+
+       /* we must delay this packet */
+       pr_debug("dequeue: mv head pkt from main to qooo and mod timer\n");
+       q->send_from_qooo = 0;
+       dly_mod_timer(q, skb);
+       __skb_queue_tail(&q->qooo, skb);
+       sch->flags |= TCQ_F_THROTTLED;
+
+       /* reset counter */
+       q->counter = 0;
+
        return NULL;
 }

@@ -153,11 +197,16 @@ static void dly_reset(struct Qdisc *sch)
        sch->q.qlen = 0;
        sch->flags &= ~TCQ_F_THROTTLED;
        del_timer(&q->timer);
+       skb_queue_purge(&q->qooo);
 }

 static void dly_timer(unsigned long arg)
 {
        struct Qdisc *sch = (struct Qdisc *)arg;
+       struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+
+       pr_debug("timer: Permit sending from qooo\n");
+       q->send_from_qooo = 1;

        sch->flags &= ~TCQ_F_THROTTLED;
        netif_schedule(sch->dev);
@@ -205,6 +254,10 @@ static int dly_change(struct Qdisc *sch,
                q->latency = qopt->latency;
                q->limit = qopt->limit;
                q->loss = qopt->loss;
+               q->gap = qopt->gap;
+
+               q->counter = 0;
+               q->send_from_qooo = 0;
        }
        return err;
 }
@@ -221,6 +274,8 @@ static int dly_init(struct Qdisc *sch, s
        q->timer.data = (unsigned long) sch;
        q->qdisc = &noop_qdisc;

+       skb_queue_head_init(&q->qooo);
+
        return dly_change(sch, opt);
 }

@@ -231,6 +286,7 @@ static void dly_destroy(struct Qdisc *sc
        del_timer(&q->timer);
        qdisc_destroy(q->qdisc);
        q->qdisc = &noop_qdisc;
+       skb_queue_purge(&q->qooo);
 }

 static int dly_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -242,6 +298,7 @@ static int dly_dump(struct Qdisc *sch, s
        qopt.latency = q->latency;
        qopt.limit = q->limit;
        qopt.loss = q->loss;
+       qopt.gap = q->gap;

        RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);

--- linux-2.6.7-bk5.orig/include/linux/pkt_sched.h 2004-06-23 12:17:59.000000000 +0300 +++ linux-2.6.7-bk5/include/linux/pkt_sched.h 2004-06-23 14:40:16.000000000 +0300
@@ -438,5 +438,6 @@ struct tc_dly_qopt
        __u32   latency;
        __u32   limit;
        __u32   loss;
+       __u32   gap;
 };
 #endif

---
Catalin(ux aka Dino) BOIE
catab at deuroconsult.ro
http://kernel.umbrella.ro/

<Prev in Thread] Current Thread [Next in Thread>