aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_netem.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r--net/sched/sch_netem.c131
1 files changed, 81 insertions, 50 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 31c29deb139d..e0c9fbe73b15 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -138,38 +138,77 @@ static long tabledist(unsigned long mu, long sigma,
138} 138}
139 139
140/* Put skb in the private delayed queue. */ 140/* Put skb in the private delayed queue. */
141static int delay_skb(struct Qdisc *sch, struct sk_buff *skb) 141static int netem_delay(struct Qdisc *sch, struct sk_buff *skb)
142{ 142{
143 struct netem_sched_data *q = qdisc_priv(sch); 143 struct netem_sched_data *q = qdisc_priv(sch);
144 struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
145 psched_tdiff_t td; 144 psched_tdiff_t td;
146 psched_time_t now; 145 psched_time_t now;
147 146
148 PSCHED_GET_TIME(now); 147 PSCHED_GET_TIME(now);
149 td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist); 148 td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist);
150 PSCHED_TADD2(now, td, cb->time_to_send);
151 149
152 /* Always queue at tail to keep packets in order */ 150 /* Always queue at tail to keep packets in order */
153 if (likely(q->delayed.qlen < q->limit)) { 151 if (likely(q->delayed.qlen < q->limit)) {
152 struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
153
154 PSCHED_TADD2(now, td, cb->time_to_send);
155
156 pr_debug("netem_delay: skb=%p now=%llu tosend=%llu\n", skb,
157 now, cb->time_to_send);
158
154 __skb_queue_tail(&q->delayed, skb); 159 __skb_queue_tail(&q->delayed, skb);
155 if (!timer_pending(&q->timer)) {
156 q->timer.expires = jiffies + PSCHED_US2JIFFIE(td);
157 add_timer(&q->timer);
158 }
159 return NET_XMIT_SUCCESS; 160 return NET_XMIT_SUCCESS;
160 } 161 }
161 162
163 pr_debug("netem_delay: queue over limit %d\n", q->limit);
164 sch->qstats.overlimits++;
162 kfree_skb(skb); 165 kfree_skb(skb);
163 return NET_XMIT_DROP; 166 return NET_XMIT_DROP;
164} 167}
165 168
169/*
170 * Move a packet that is ready to send from the delay holding
171 * list to the underlying qdisc.
172 */
173static int netem_run(struct Qdisc *sch)
174{
175 struct netem_sched_data *q = qdisc_priv(sch);
176 struct sk_buff *skb;
177 psched_time_t now;
178
179 PSCHED_GET_TIME(now);
180
181 skb = skb_peek(&q->delayed);
182 if (skb) {
183 const struct netem_skb_cb *cb
184 = (const struct netem_skb_cb *)skb->cb;
185 long delay
186 = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
187 pr_debug("netem_run: skb=%p delay=%ld\n", skb, delay);
188
189 /* if more time remaining? */
190 if (delay > 0) {
191 mod_timer(&q->timer, jiffies + delay);
192 return 1;
193 }
194
195 __skb_unlink(skb, &q->delayed);
196
197 if (q->qdisc->enqueue(skb, q->qdisc)) {
198 sch->q.qlen--;
199 sch->qstats.drops++;
200 }
201 }
202
203 return 0;
204}
205
166static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) 206static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
167{ 207{
168 struct netem_sched_data *q = qdisc_priv(sch); 208 struct netem_sched_data *q = qdisc_priv(sch);
169 struct sk_buff *skb2;
170 int ret; 209 int ret;
171 210
172 pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); 211 pr_debug("netem_enqueue skb=%p\n", skb);
173 212
174 /* Random packet drop 0 => none, ~0 => all */ 213 /* Random packet drop 0 => none, ~0 => all */
175 if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { 214 if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
@@ -180,11 +219,21 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
180 } 219 }
181 220
182 /* Random duplication */ 221 /* Random duplication */
183 if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor) 222 if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) {
184 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { 223 struct sk_buff *skb2;
185 pr_debug("netem_enqueue: dup %p\n", skb2); 224
225 skb2 = skb_clone(skb, GFP_ATOMIC);
226 if (skb2 && netem_delay(sch, skb2) == NET_XMIT_SUCCESS) {
227 struct Qdisc *qp;
228
229 /* Since one packet can generate two packets in the
230 * queue, the parent's qlen accounting gets confused,
231 * so fix it.
232 */
233 qp = qdisc_lookup(sch->dev, TC_H_MAJ(sch->parent));
234 if (qp)
235 qp->q.qlen++;
186 236
187 if (delay_skb(sch, skb2)) {
188 sch->q.qlen++; 237 sch->q.qlen++;
189 sch->bstats.bytes += skb2->len; 238 sch->bstats.bytes += skb2->len;
190 sch->bstats.packets++; 239 sch->bstats.packets++;
@@ -202,7 +251,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
202 ret = q->qdisc->enqueue(skb, q->qdisc); 251 ret = q->qdisc->enqueue(skb, q->qdisc);
203 } else { 252 } else {
204 q->counter = 0; 253 q->counter = 0;
205 ret = delay_skb(sch, skb); 254 ret = netem_delay(sch, skb);
255 netem_run(sch);
206 } 256 }
207 257
208 if (likely(ret == NET_XMIT_SUCCESS)) { 258 if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -212,6 +262,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
212 } else 262 } else
213 sch->qstats.drops++; 263 sch->qstats.drops++;
214 264
265 pr_debug("netem: enqueue ret %d\n", ret);
215 return ret; 266 return ret;
216} 267}
217 268
@@ -241,56 +292,35 @@ static unsigned int netem_drop(struct Qdisc* sch)
241 return len; 292 return len;
242} 293}
243 294
244/* Dequeue packet.
245 * Move all packets that are ready to send from the delay holding
246 * list to the underlying qdisc, then just call dequeue
247 */
248static struct sk_buff *netem_dequeue(struct Qdisc *sch) 295static struct sk_buff *netem_dequeue(struct Qdisc *sch)
249{ 296{
250 struct netem_sched_data *q = qdisc_priv(sch); 297 struct netem_sched_data *q = qdisc_priv(sch);
251 struct sk_buff *skb; 298 struct sk_buff *skb;
299 int pending;
300
301 pending = netem_run(sch);
252 302
253 skb = q->qdisc->dequeue(q->qdisc); 303 skb = q->qdisc->dequeue(q->qdisc);
254 if (skb) 304 if (skb) {
305 pr_debug("netem_dequeue: return skb=%p\n", skb);
255 sch->q.qlen--; 306 sch->q.qlen--;
307 sch->flags &= ~TCQ_F_THROTTLED;
308 }
309 else if (pending) {
310 pr_debug("netem_dequeue: throttling\n");
311 sch->flags |= TCQ_F_THROTTLED;
312 }
313
256 return skb; 314 return skb;
257} 315}
258 316
259static void netem_watchdog(unsigned long arg) 317static void netem_watchdog(unsigned long arg)
260{ 318{
261 struct Qdisc *sch = (struct Qdisc *)arg; 319 struct Qdisc *sch = (struct Qdisc *)arg;
262 struct netem_sched_data *q = qdisc_priv(sch);
263 struct net_device *dev = sch->dev;
264 struct sk_buff *skb;
265 psched_time_t now;
266
267 pr_debug("netem_watchdog: fired @%lu\n", jiffies);
268
269 spin_lock_bh(&dev->queue_lock);
270 PSCHED_GET_TIME(now);
271
272 while ((skb = skb_peek(&q->delayed)) != NULL) {
273 const struct netem_skb_cb *cb
274 = (const struct netem_skb_cb *)skb->cb;
275 long delay
276 = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now));
277 pr_debug("netem_watchdog: skb %p@%lu %ld\n",
278 skb, jiffies, delay);
279 320
280 /* if more time remaining? */ 321 pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen);
281 if (delay > 0) { 322 sch->flags &= ~TCQ_F_THROTTLED;
282 mod_timer(&q->timer, jiffies + delay); 323 netif_schedule(sch->dev);
283 break;
284 }
285 __skb_unlink(skb, &q->delayed);
286
287 if (q->qdisc->enqueue(skb, q->qdisc)) {
288 sch->q.qlen--;
289 sch->qstats.drops++;
290 }
291 }
292 qdisc_run(dev);
293 spin_unlock_bh(&dev->queue_lock);
294} 324}
295 325
296static void netem_reset(struct Qdisc *sch) 326static void netem_reset(struct Qdisc *sch)
@@ -301,6 +331,7 @@ static void netem_reset(struct Qdisc *sch)
301 skb_queue_purge(&q->delayed); 331 skb_queue_purge(&q->delayed);
302 332
303 sch->q.qlen = 0; 333 sch->q.qlen = 0;
334 sch->flags &= ~TCQ_F_THROTTLED;
304 del_timer_sync(&q->timer); 335 del_timer_sync(&q->timer);
305} 336}
306 337