Пример #1
0
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);
}
Пример #2
0
static struct sk_buff *netem_dequeue(struct Qdisc *sch)
{
	struct netem_sched_data *q = qdisc_priv(sch);
	struct sk_buff *skb;

	skb = q->qdisc->dequeue(q->qdisc);
	if (skb) {
		const struct netem_skb_cb *cb
			= (const struct netem_skb_cb *)skb->cb;
		psched_time_t now;

		/* if more time remaining? */
		PSCHED_GET_TIME(now);

		if (PSCHED_TLESS(cb->time_to_send, now)) {
			pr_debug("netem_dequeue: return skb=%p\n", skb);
			sch->q.qlen--;
			sch->flags &= ~TCQ_F_THROTTLED;
			return skb;
		} else {
			psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);

			if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
				qdisc_tree_decrease_qlen(q->qdisc, 1);
				sch->qstats.drops++;
				printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
				       q->qdisc->ops->id);
			}

			mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
			sch->flags |= TCQ_F_THROTTLED;
		}
	}

	return NULL;
}
Пример #3
0
/* Put skb in the private delayed queue. */
static int delay_skb(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)) {
		__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;
	}

	kfree_skb(skb);
	return NET_XMIT_DROP;
}
Пример #4
0
static struct sk_buff *
tbf_dequeue(struct Qdisc* sch)
{
	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
	struct sk_buff *skb;
	
	skb = __skb_dequeue(&sch->q);

	if (skb) {
		psched_time_t now;
		long toks;
		long ptoks = 0;

		PSCHED_GET_TIME(now);

		toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer, 0);

		if (q->P_tab) {
			ptoks = toks + q->ptokens;
			if (ptoks > (long)q->mtu)
				ptoks = q->mtu;
			ptoks -= L2T_P(q, skb->len);
		}
		toks += q->tokens;
		if (toks > (long)q->buffer)
			toks = q->buffer;
		toks -= L2T(q, skb->len);

		if ((toks|ptoks) >= 0) {
			q->t_c = now;
			q->tokens = toks;
			q->ptokens = ptoks;
			sch->stats.backlog -= skb->len;
			return skb;
		}

		if (!sch->dev->tbusy) {
			long delay = PSCHED_US2JIFFIE(max(-toks, -ptoks));

			if (delay == 0)
				delay = 1;

			del_timer(&q->wd_timer);
			q->wd_timer.expires = jiffies + delay;
			add_timer(&q->wd_timer);
		}

		/* Maybe we have a shorter packet in the queue,
		   which can be sent now. It sounds cool,
		   but, however, this is wrong in principle.
		   We MUST NOT reorder packets under these circumstances.

		   Really, if we split the flow into independent
		   subflows, it would be a very good solution.
		   This is the main idea of all FQ algorithms
		   (cf. CSZ, HPFQ, HFCS)
		 */
		__skb_queue_head(&sch->q, skb);

		sch->stats.overlimits++;
	}
	return NULL;
}