static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, void *data) { struct net_device *dev; struct net_device_stats *stats; struct sk_buff *skb2 = NULL; struct Qdisc *q; unsigned int index = skb->imq_flags&IMQ_F_IFMASK; int ret = -1; if (index > numdevs) return -1; dev = imq_devs + index; if (!(dev->flags & IFF_UP)) { skb->imq_flags = 0; nf_reinject(skb, info, NF_ACCEPT); return 0; } dev->last_rx = jiffies; if (skb->destructor) { skb2 = skb; skb = skb_clone(skb, GFP_ATOMIC); if (!skb) return -1; } skb_push(skb, IMQ_HH_LEN(info)); skb->nf_info = info; stats = (struct net_device_stats *)dev->priv; stats->rx_bytes+= skb->len; stats->rx_packets++; spin_lock_bh(&dev->queue_lock); q = dev->qdisc; if (q->enqueue) { q->enqueue(skb_get(skb), q); if (skb_shared(skb)) { skb->destructor = imq_skb_destructor; kfree_skb(skb); ret = 0; } } qdisc_run(dev); spin_unlock_bh(&dev->queue_lock); if (skb2) kfree_skb(ret ? skb : skb2); return ret; }
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); }