/* this functions used only in no_bxm mode, * it's not implemented in netdevice.h so we have it here * based on netif_tx_lock() */ static inline int vnic_netif_tx_trylock(struct net_device *dev) { int i, cpu; spin_lock(&dev->tx_global_lock); cpu = smp_processor_id(); for (i = 0; i < dev->num_tx_queues; ++i) { struct netdev_queue *txq = netdev_get_tx_queue(dev, i); if (__netif_tx_trylock(txq)) { set_bit(__QUEUE_STATE_FROZEN, &txq->state); __netif_tx_unlock(txq); } else { goto unlock; } } return 1; unlock: /* based on netif_tx_unlock() */ for (--i; i >= 0; --i) { struct netdev_queue *txq = netdev_get_tx_queue(dev, i); clear_bit(__QUEUE_STATE_FROZEN, &txq->state); if (!test_bit(QUEUE_STATE_ANY_XOFF, &txq->state)) __netif_schedule(txq->qdisc); } spin_unlock(&dev->tx_global_lock); return 0; }
void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; /* 循环调用qdisc_restart发送数据 这个函数qdisc_restart是真正发送数据包的函数 它从队列上取下一个帧,然后尝试将它发送出去 若发送失败则一般是重新入队。 此函数返回值为:发送成功时返回剩余队列长度 发送失败时返回0(若发送成功且剩余队列长度为0也返回0) */ while (qdisc_restart(q)) { /* * Postpone processing if * 1. another process needs the CPU; * 2. we've been doing it for too long. */ if (need_resched() || jiffies != start_time) { //当需要进行调度或者时间超过了1个时间片的时候就退出循环,退出之前发出软中断请求 __netif_schedule(q); break; } } clear_bit(__QDISC_STATE_RUNNING, &q->state); }
static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { q->gso_skb = skb; q->qstats.requeues++; __netif_schedule(q); return 0; }
static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { q->gso_skb = skb; q->qstats.requeues++; q->q.qlen++; /* it's still part of the queue */ __netif_schedule(q); return 0; }
static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { if (unlikely(skb->next)) q->gso_skb = skb; else q->ops->requeue(skb, q); __netif_schedule(q); return 0; }
void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; while (qdisc_restart(q)) { if (need_resched() || jiffies != start_time) { __netif_schedule(q); break; } } clear_bit(__QDISC_STATE_RUNNING, &q->state); }
static inline int __dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { while (skb) { struct sk_buff *next = skb->next; __skb_queue_tail(&q->gso_skb, skb); q->qstats.requeues++; qdisc_qstats_backlog_inc(q, skb); q->q.qlen++; /* it's still part of the queue */ skb = next; } __netif_schedule(q); return 0; }
void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; while (qdisc_restart(q)) { /* * Postpone processing if * 1. another process needs the CPU; * 2. we've been doing it for too long. */ if (need_resched() || jiffies != start_time) { __netif_schedule(q); break; } } clear_bit(__QDISC_STATE_RUNNING, &q->state); }
void __qdisc_run(struct Qdisc *q) { int quota = dev_tx_weight; int packets; while (qdisc_restart(q, &packets)) { /* * Ordered by possible occurrence: Postpone processing if * 1. we've exceeded packet quota * 2. another process needs the CPU; */ quota -= packets; if (quota <= 0 || need_resched()) { __netif_schedule(q); break; } } }
void __qdisc_run(struct Qdisc *q) { int quota = weight_p; while (qdisc_restart(q)) { /* * Ordered by possible occurrence: Postpone processing if * 1. we've exceeded packet quota * 2. another process needs the CPU; */ if (--quota <= 0 || need_resched()) { __netif_schedule(q); break; } } qdisc_run_end(q); }
void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; while (qdisc_restart(q)) { /* * Postpone processing if * 1. another process needs the CPU; * 2. we've been doing it for too long. */ if (need_resched() || jiffies != start_time) { __netif_schedule(q); break; } } qdisc_run_end(q); }
static inline int dev_requeue_skb_locked(struct sk_buff *skb, struct Qdisc *q) { spinlock_t *lock = qdisc_lock(q); spin_lock(lock); while (skb) { struct sk_buff *next = skb->next; __skb_queue_tail(&q->gso_skb, skb); qdisc_qstats_cpu_requeues_inc(q); qdisc_qstats_cpu_backlog_inc(q, skb); qdisc_qstats_cpu_qlen_inc(q); skb = next; } spin_unlock(lock); __netif_schedule(q); return 0; }
static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num) { struct net_device *dev; struct sk_buff *skb_orig, *skb, *skb_shared; struct Qdisc *q; struct netdev_queue *txq; spinlock_t *root_lock; int users, index; int retval = -EINVAL; unsigned int orig_queue_index; index = entry->skb->imq_flags & IMQ_F_IFMASK; if (unlikely(index > numdevs - 1)) { if (net_ratelimit()) printk(KERN_WARNING "IMQ: invalid device specified, highest is %u\n", numdevs - 1); retval = -EINVAL; goto out; } /* check for imq device by index from cache */ dev = imq_devs_cache[index]; if (unlikely(!dev)) { char buf[8]; /* get device by name and cache result */ snprintf(buf, sizeof(buf), "imq%d", index); dev = dev_get_by_name(&init_net, buf); if (unlikely(!dev)) { /* not found ?!*/ BUG(); retval = -ENODEV; goto out; } imq_devs_cache[index] = dev; dev_put(dev); } if (unlikely(!(dev->flags & IFF_UP))) { entry->skb->imq_flags = 0; nf_reinject(entry, NF_ACCEPT); retval = 0; goto out; } dev->last_rx = jiffies; skb = entry->skb; skb_orig = NULL; /* skb has owner? => make clone */ if (unlikely(skb->destructor)) { skb_orig = skb; skb = skb_clone(skb, GFP_ATOMIC); if (unlikely(!skb)) { retval = -ENOMEM; goto out; } entry->skb = skb; } skb->nf_queue_entry = entry; dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; if (!skb->dev) { /* skb->dev == NULL causes problems, try the find cause. */ if (net_ratelimit()) { dev_warn(&dev->dev, "received packet with skb->dev == NULL\n"); dump_stack(); } skb->dev = dev; } /* Disables softirqs for lock below */ rcu_read_lock_bh(); /* Multi-queue selection */ orig_queue_index = skb_get_queue_mapping(skb); txq = imq_select_queue(dev, skb); q = rcu_dereference(txq->qdisc); if (unlikely(!q->enqueue)) goto packet_not_eaten_by_imq_dev; root_lock = qdisc_lock(q); spin_lock(root_lock); users = atomic_read(&skb->users); skb_shared = skb_get(skb); /* increase reference count by one */ skb_save_cb(skb_shared); /* backup skb->cb, as qdisc layer will overwrite it */ qdisc_enqueue_root(skb_shared, q); /* might kfree_skb */ if (likely(atomic_read(&skb_shared->users) == users + 1)) { kfree_skb(skb_shared); /* decrease reference count by one */ skb->destructor = &imq_skb_destructor; /* cloned? */ if (unlikely(skb_orig)) kfree_skb(skb_orig); /* free original */ spin_unlock(root_lock); rcu_read_unlock_bh(); /* schedule qdisc dequeue */ __netif_schedule(q); retval = 0; goto out; } else { skb_restore_cb(skb_shared); /* restore skb->cb */ skb->nf_queue_entry = NULL; /* qdisc dropped packet and decreased skb reference count of * skb, so we don't really want to and try refree as that would * actually destroy the skb. */ spin_unlock(root_lock); goto packet_not_eaten_by_imq_dev; } packet_not_eaten_by_imq_dev: skb_set_queue_mapping(skb, orig_queue_index); rcu_read_unlock_bh(); /* cloned? restore original */ if (unlikely(skb_orig)) { kfree_skb(skb); entry->skb = skb_orig; } retval = -1; out: return retval; }
static int prio_tune(struct Qdisc *sch, struct nlattr *opt) { struct prio_sched_data *q = qdisc_priv(sch); struct tc_prio_qopt *qopt; int i; int flow_change = 0; if (nla_len(opt) < sizeof(*qopt)) return -EINVAL; qopt = nla_data(opt); if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2) return -EINVAL; for (i = 0; i <= TC_PRIO_MAX; i++) { if (qopt->priomap[i] >= qopt->bands) return -EINVAL; } sch_tree_lock(sch); if (q->enable_flow != qopt->enable_flow) { q->enable_flow = qopt->enable_flow; flow_change = 1; } q->bands = qopt->bands; memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); for (i = q->bands; i < TCQ_PRIO_BANDS; i++) { struct Qdisc *child = q->queues[i]; q->queues[i] = &noop_qdisc; if (child != &noop_qdisc) { qdisc_tree_decrease_qlen(child, child->q.qlen); qdisc_destroy(child); } } sch_tree_unlock(sch); for (i = 0; i < q->bands; i++) { if (q->queues[i] == &noop_qdisc) { struct Qdisc *child, *old; child = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, TC_H_MAKE(sch->handle, i + 1)); if (child) { sch_tree_lock(sch); old = q->queues[i]; q->queues[i] = child; if (old != &noop_qdisc) { qdisc_tree_decrease_qlen(old, old->q.qlen); qdisc_destroy(old); } sch_tree_unlock(sch); } } } /* Schedule qdisc when flow re-enabled */ if (flow_change && q->enable_flow) { if (!test_bit(__QDISC_STATE_DEACTIVATED, &sch->state)) __netif_schedule(qdisc_root(sch)); } return 0; }