引用


一. OverArch

  • qdisc_lock(q) serializes queue accesses for this queue.
  • HARD_TX_LOCK(dev, txq, smp_processor_id()) -- txq->_xmit_lock,会 lock dev_hard_start_xmit() flow,即表示NIC driver的 ndo_start_xmit()在实现上必须是原子的,不能有阻塞。netif_tx_lock serializes accesses to device driver.

1.1 Overall flow

1.2 LLD

  • 注意:
  • 有两个context在执行 qdisc_run(),即执行qdisc->dequeue发包操作。
    • __dev_xmit_skb() -- 即跑在用户进程的系统调用中,占用的是 系统时间;或者 TSQ- tasklet (only for tcp)。
    • NET_TX_SOFTIRQ软中断 -- 软中断 si 的时间或者softirq线程时间。
  • qdisc dequeu,enqueue数据时,会持有qdisc的锁。即注意 并发情况,即多个txq的mq的优势。
  • 会通过qdisc->state来判断是否可进行qdisc的dequeue操作。
  •  running seqcount guarantees only one CPU can process this qdisc at a time. qdisc_lock(q) serializes queue accesses for this queue.
  • 会通过 qdisc->running来判断是否是第一次进行qdisc,从而,是否进行enqueue。qdisc_run_begin(), qdisc_is_running。
  • 会通过 qdisc->busylock和qdisc_is_running()来加速 qdisc->q.lock 的获取。
  • 实际调用网卡的ndo_xmit()前,会获取 txq->_xmit_lock。即 HARD_TX_LOCK() ndo_xmit()的routine中不能有等待睡眠的api操作。netif_tx_lock serializes accesses to device driver.
  • qdisc_lock(q) and netif_tx_lock are mutually exclusive, if one is grabbed, another must be free.
  • 发送时,会查看该txq是否有被stop或者frozen。netif_tx_stop_queue()
  • txq的qdisc也是有上限的,例如 1000。但可以通过 ip link set txqueuelen 10000 dev ens37 设置。
  • 当driver发送数据失败,即ndo_xmit() 返回 EBUSY时,qdisc层会将skb再次enqueue,等待下次发送。会通过软中断继续发送。

二. qdisc

  • Qdisc: how to queue the packets
  • Class: tied with qdiscs to form a hierarchy
  • Filter: how to classify or filter the packets
  • Action: how to deal with the matched packets

2.1 按照single queue和multiple queue分类

single queue:表示NIC 只有一个tx queue,一般由硬件决定。

multiple queue: 表示NIC 由多个tx queue。

在alloc_etherdev_mq()等申请net device时,就决定了tx queue的数量。

当然,还可用 netif_set_real_num_tx_queues()来报告真实的queue。

 * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
 * greater than real_num_tx_queues stale skbs on the qdisc must be flushed.

内核目前Single queue qdisc, 包括:

1. Classless Queuing Disciplines (qdiscs)

  • choke, codel, [p|b]fifo, fq, fq_codel, fq_pie, gred, hhf, ingress, mqprio, multiq, netem, pfifo_fast, pie, red, rr, sfb, sfq, tbf

2. Classful Queuing Disciplines (qdiscs)

  • ATM, CBQ, DRR, DSMARK, ETS, HFSC, HTB, PRIO, QFQ

内核目前multiple queue qdisc, 包括:

  • mq qdisc (/net/sched/sch_mq.c)
  • mqprio qdisc (/net/sched/sch_mqprio.c)
  • multiq qdisc (/net/sched/sch_multiq.c)

The mq qdisc is a dummy qdisc which sets up an array of pfifo_fast queues as a Traffic Control tc class under the root mq qdisc. One pfifo_fast queue is created for each hardware queue.

2.2 init flow

  • subsys_initcall(pktsched_init);   - net/sched/sch_api.h

采用register_qdisc()接口来注册一些算法到全局链表qdisc_base中。

  • int register_netdevice(struct net_device *dev) - /net/core/dev.c

在各NIC driver注册时调用。里面会再调用 dev_init_scheduler(dev) 进行初始化为noop_qdisc

noop_qdisc算法什么也不做,enqueue函数为丢弃数据包。

  • int dev_open(struct net_device *dev, struct netlink_ext_ack *extack) - /net/core/dev.c

当用ifconfig xxx up网卡后,会调用dev_open(),最终分配默认的qdisc算法给tx queue。

single tx queue: pfifo_fast

multiple tx queue: mq

默认的qdisc 由 CONFIG_DEFAULT_NET_SCH指定 -- sch_default_qdisc()

可通过 cat /proc/sys/net/core/default_qdisc 查看或更改。

三. TC简介

tc可以使用以下命令对QDisc、类和过滤器进行操作:

add,在一个节点里加入一个QDisc、类或者过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个QDisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。

remove,删除有某个句柄(handle)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。

change,以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一定节点的位置。

replace,对一个现有节点进行近于原子操作的删除/添加。如果节点不存在,这个命令就会建立节点。

link,只适用于DQisc,替代一个现有的节点。

tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]

tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]

tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id

tc [-s | -d ] qdisc show [ dev DEV ]

tc [-s | -d ] class show dev DEV tc filter show dev DEV

即可看出目前ubuntu默认用的是 fq_codel qdisc。

Logo

更多推荐