void dev_activate(struct net_device *dev)
{
if (dev->qdisc == &noop_qdisc)
/*为每个发送队列设置默认的流量控制接口 */
netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);
if (dev_ingress_queue(dev))
transition_one_qdisc(dev, dev_ingress_queue(dev), NULL);
static void attach_default_qdiscs(struct net_device *dev)
/*单队列流量控制 */
if (!netif_is_multiqueue(dev) || dev->tx_queue_len == 0) {
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
dev->qdisc = txq->qdisc_sleeping;
atomic_inc(&dev->qdisc->refcnt);
} else {
多队列流量控制,root discs设置为mq_qdisc_ops */
qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT);
if (qdisc) {
qdisc->ops->attach(qdisc);
dev->qdisc = qdisc;
}
}
truct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
struct Qdisc_ops *ops, unsigned int parentid)
struct Qdisc *sch;
表示一个流量控制规则 */
sch = qdisc_alloc(dev_queue, ops);
if (IS_ERR(sch))
goto errout;
sch->parent = parentid;
/*初始化流量控制规则 */
if (!ops->init || ops->init(sch, NULL) == 0)
return sch;
qdisc_destroy(sch);
return NULL;
sstatic int mq_init(struct Qdisc *sch, struct nlattr *opt)
struct net_device *dev = qdisc_dev(sch);
struct mq_sched *priv = qdisc_priv(sch);
struct netdev_queue *dev_queue;
struct Qdisc *qdisc;
unsigned int ntx;
为根流量控制初始化函数 */
if (sch->parent != TC_H_ROOT)
return -EOPNOTSUPP;
/*一定是多队列 */
if (!netif_is_multiqueue(dev))
return -EOPNOTSUPP;
为每个队列分配流量控制 */
/* pre-allocate qdiscs, attachment can't fail */
priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
GFP_KERNEL);
if (priv->qdiscs == NULL)
return -ENOMEM;
/*依次设置流量控制规则为pfifo_fast_ops */
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
dev_queue = netdev_get_tx_queue(dev, ntx);
/*这里递归调用qdisc_create_dflt函数 */
qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops,
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(ntx + 1)));
if (qdisc == NULL)
goto err;
priv->qdiscs[ntx] = qdisc;
qdisc->flags |= TCQ_F_ONETXQUEUE;
}
sch->flags |= TCQ_F_MQROOT;
return 0;
mq_destroy(sch);
return -ENOMEM;
static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
int prio;
struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
skb_queue_head_init(band2list(priv, prio));
/* Can by-pass the queue discipline */
qdisc->flags |= TCQ_F_CAN_BYPASS;
return 0;