hi i tried the example given on the examples page to duplicate selected traffic like tc qdisc add dev eth0 root handle 1: prio tc qdisc add dev eth0 parent 1:3 handle 3: netem duplicate 40% tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dst 11.0.2.2 flowid 1:3 when i ping from 11.0.2.2 to this interface my machine hangs. the same thing works for drop or delay. i would appreciate if someone can tell me what i am doing wrong. thanks. __________________________________ Do you Yahoo!? Yahoo! Small Business - Try our new resources site! http://smallbusiness.yahoo.com/resources/
js si wrote:> hi > > i tried the example given on the examples page to > duplicate selected traffic like > > tc qdisc add dev eth0 root handle 1: prio > tc qdisc add dev eth0 parent 1:3 handle 3: netem > duplicate 40% > tc filter add dev eth0 protocol ip parent 1:0 prio 3 > u32 match ip dst 11.0.2.2 flowid 1:3 > > when i ping from 11.0.2.2 to this interface my machine > hangs. the same thing works for drop or delay. > > i would appreciate if someone can tell me what i am > doing wrong.Using netem with an upper qdisc screws up the upper qdisc''s q.qlen counter and qdisc_run() tries to dequeue it indefinitely. I don''t know whether netem is intended to be useable only as top-level qdisc, if so it should make sure that it really is used this way to avoid hanging the system. Regards Patrick
On Wed, 30 Mar 2005 10:05:04 -0800 (PST) js si <nistnet_user@yahoo.com> wrote:> hi > > i tried the example given on the examples page to > duplicate selected traffic like > > tc qdisc add dev eth0 root handle 1: prio > tc qdisc add dev eth0 parent 1:3 handle 3: netem > duplicate 40% > tc filter add dev eth0 protocol ip parent 1:0 prio 3 > u32 match ip dst 11.0.2.2 flowid 1:3 >Try this. qdisc_restart() has a bug. It will spin until packet becomes available, which is wrong. This effects both netem and tbf, maybe other qdisc as well. --- linux-2.6/net/sched/sch_generic.c 2005-03-14 14:30:52.000000000 -0800 +++ tcp-2.6/net/sched/sch_generic.c 2005-04-04 10:28:31.000000000 -0700 @@ -176,10 +176,10 @@ int qdisc_restart(struct net_device *dev requeue: q->ops->requeue(skb, q); - netif_schedule(dev); - return 1; + netif_schedule(dev); + return q->q.qlen; } - return q->q.qlen; + return 0; } static void dev_watchdog(unsigned long arg)
Stephen Hemminger
2005-Apr-04 21:04 UTC
Re: [Netem] Re: netem with prio hangs on duplicate
On Mon, 4 Apr 2005 11:00:36 -0700 Stephen Hemminger <shemminger@osdl.org> wrote:> On Wed, 30 Mar 2005 10:05:04 -0800 (PST) > js si <nistnet_user@yahoo.com> wrote: > > > hi > > > > i tried the example given on the examples page to > > duplicate selected traffic like > > > > tc qdisc add dev eth0 root handle 1: prio > > tc qdisc add dev eth0 parent 1:3 handle 3: netem > > duplicate 40% > > tc filter add dev eth0 protocol ip parent 1:0 prio 3 > > u32 match ip dst 11.0.2.2 flowid 1:3 > > > > Try this. qdisc_restart() has a bug. It will spin until packet becomes available, which > is wrong. This effects both netem and tbf, maybe other qdisc as well. >Never mind, that patch is crap...
On Wed, 30 Mar 2005 10:05:04 -0800 (PST) js si <nistnet_user@yahoo.com> wrote:> hi > > i tried the example given on the examples page to > duplicate selected traffic like > > tc qdisc add dev eth0 root handle 1: prio > tc qdisc add dev eth0 parent 1:3 handle 3: netem > duplicate 40% > tc filter add dev eth0 protocol ip parent 1:0 prio 3 > u32 match ip dst 11.0.2.2 flowid 1:3 > > when i ping from 11.0.2.2 to this interface my machine > hangs. the same thing works for drop or delay. > > i would appreciate if someone can tell me what i am > doing wrong.I can''t reproduce this on my SMP box, will try UP. Could you get a backtrace with sysrq-P and sysrq-T?
Try this alternative, it changes where netem does the delaying and doesn''t do queuing in the timer routine. It is stable for the basic tests, but I still consider it experimental and needs more testing. Patch against the version of sch_netem.c in 2.6.12-rc2 --- linux-2.6.12-rc2/net/sched/sch_netem.c 2005-04-04 09:39:41.000000000 -0700 +++ netem-2.6.12-rc2/net/sched/sch_netem.c 2005-04-06 15:39:16.000000000 -0700 @@ -138,38 +138,78 @@ static long tabledist(unsigned long mu, } /* Put skb in the private delayed queue. */ -static int delay_skb(struct Qdisc *sch, struct sk_buff *skb) +static int netem_delay(struct Qdisc *sch, struct sk_buff *skb) { 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); 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)) { + struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; + + PSCHED_TADD2(now, td, cb->time_to_send); + + pr_debug("netem_delay: skb=%p now=%llu tosend=%llu\n", skb, + now, cb->time_to_send); + __skb_queue_tail(&q->delayed, skb); - if (!timer_pending(&q->timer)) { - q->timer.expires = jiffies + PSCHED_US2JIFFIE(td); - add_timer(&q->timer); - } return NET_XMIT_SUCCESS; } + pr_debug("netem_delay: queue over limit %d\n", q->limit); + sch->qstats.overlimits++; kfree_skb(skb); return NET_XMIT_DROP; } +/* + * Move a packet that is ready to send from the delay holding + * list to the underlying qdisc. + */ +static int netem_run(struct Qdisc *sch) +{ + struct netem_sched_data *q = qdisc_priv(sch); + struct sk_buff *skb; + psched_time_t now; + + PSCHED_GET_TIME(now); + + skb = skb_peek(&q->delayed); + if (skb) { + 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_run: skb=%p delay=%ld\n", skb, delay); + + /* if more time remaining? */ + if (delay > 0) { + mod_timer(&q->timer, jiffies + delay); + return 1; + } + + __skb_unlink(skb, &q->delayed); + + if (q->qdisc->enqueue(skb, q->qdisc)) { + sch->q.qlen--; + sch->qstats.drops++; + } + } + + return 0; +} + static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct netem_sched_data *q = qdisc_priv(sch); struct sk_buff *skb2; int ret; - pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); + pr_debug("netem_enqueue skb=%p\n", skb); /* Random packet drop 0 => none, ~0 => all */ if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { @@ -184,7 +224,7 @@ static int netem_enqueue(struct sk_buff && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { pr_debug("netem_enqueue: dup %p\n", skb2); - if (delay_skb(sch, skb2)) { + if (netem_delay(sch, skb2)) { sch->q.qlen++; sch->bstats.bytes += skb2->len; sch->bstats.packets++; @@ -202,7 +242,8 @@ static int netem_enqueue(struct sk_buff ret = q->qdisc->enqueue(skb, q->qdisc); } else { q->counter = 0; - ret = delay_skb(sch, skb); + ret = netem_delay(sch, skb); + netem_run(sch); } if (likely(ret == NET_XMIT_SUCCESS)) { @@ -241,56 +282,35 @@ static unsigned int netem_drop(struct Qd return len; } -/* Dequeue packet. - * Move all packets that are ready to send from the delay holding - * list to the underlying qdisc, then just call dequeue - */ static struct sk_buff *netem_dequeue(struct Qdisc *sch) { struct netem_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; + int pending; + + pending = netem_run(sch); skb = q->qdisc->dequeue(q->qdisc); - if (skb) + if (skb) { + pr_debug("netem_dequeue: return skb=%p\n", skb); sch->q.qlen--; + sch->flags &= ~TCQ_F_THROTTLED; + } + else if (pending) { + pr_debug("netem_dequeue: throttling\n"); + sch->flags |= TCQ_F_THROTTLED; + } + 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_watchdog: skb %p@%lu %ld\n", - skb, jiffies, delay); - - /* if more time remaining? */ - if (delay > 0) { - mod_timer(&q->timer, jiffies + delay); - break; - } - __skb_unlink(skb, &q->delayed); - - if (q->qdisc->enqueue(skb, q->qdisc)) { - sch->q.qlen--; - sch->qstats.drops++; - } - } - qdisc_run(dev); - spin_unlock_bh(&dev->queue_lock); + pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen); + sch->flags &= ~TCQ_F_THROTTLED; + netif_schedule(sch->dev); } static void netem_reset(struct Qdisc *sch) @@ -301,6 +321,7 @@ static void netem_reset(struct Qdisc *sc skb_queue_purge(&q->delayed); sch->q.qlen = 0; + sch->flags &= ~TCQ_F_THROTTLED; del_timer_sync(&q->timer); }