Linux - 网络子系统 - 网络设备子系统:TX
引用链路层输出 - qdisc多队列网卡简介以及Linux通过网卡发送数据包源码解读Linux多队列网卡Linux TCP队列相关参数的总结Queueing in the Linux Network StackLinux XPS实现linux kernel 网络协议栈之xps特性详解What is the mq qdisc in tc Traffic Control?Linux 高级流控 - IB
引用
- 链路层输出 - qdisc
- 链路层的输出
- 多队列网卡简介以及Linux通过网卡发送数据包源码解读
- Linux多队列网卡
- Linux TCP队列相关参数的总结
- Queueing in the Linux Network Stack
- Linux XPS实现
- linux kernel 网络协议栈之xps特性详解
- What is the mq qdisc in tc Traffic Control?
- Linux 高级流控 - IBM
- 网卡中断及多队列
- Cgroup - Linux 的网络资源隔离
- Linux 网络堆栈的排队机制
- 理解fq_codel之概述
- Linux内核--网络栈实现分析(一)--网络栈初始化
- HOWTO for multiqueue network device support
- Multiqueue networking
- Multi-queue network interfaces with SMP on Linux
- MQPRIO - Multiqueue Priority Qdisc (Offloaded Hardware QOS)
- Monitoring and Tuning the Linux Networking Stack: Sending Data
- Monitoring and Tuning the Linux Networking Stack: Receiving Data
- Documentation: networking: cpsw: add MQPRIO & CBS offload examples
- tc - show / manipulate traffic control settings
- Linux Traffic Control
一. 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。
更多推荐
所有评论(0)