Linux TC流量控制常用功能笔记

Posted by NoPanic on Mon, Apr 17, 2023

什么是TC

TC(Traffic Control)是Linux内核提供的流量控制工具,它可以对网络接口上的数据包进行队列、调度、限流、延迟等各种操作。TC通过队列规定(Queueing Discipline,简称qdisc)来实现对网络流量的精细控制。

TC主要功能包括:

  • 带宽控制
  • 延迟模拟
  • 丢包模拟
  • 包重排
  • 流量整形

基本概念

QDisc(队列规定)

QDisc是TC的核心概念,它定义了数据包在网络接口上的排队和发送规则。Linux内核支持多种类型的qdisc:

  • pfifo_fast:默认的qdisc,简单的FIFO队列
  • netem:网络仿真qdisc,用于模拟各种网络条件
  • tbf:令牌桶过滤器,用于限制带宽
  • htb:层次化令牌桶,支持复杂的带宽分配
  • cbq:基于类的队列,用于复杂的流量控制
  • prio:优先级队列

Handle和Parent

每个qdisc都有一个handle(句柄),格式为major:minor

  • root:根qdisc,handle通常是1:0
  • parent:指定父qdisc的handle

常用命令格式

 1# 添加qdisc
 2tc qdisc add dev <interface> <position> <qdisc-type> [parameters]
 3
 4# 删除qdisc  
 5tc qdisc del dev <interface> <position>
 6
 7# 查看qdisc
 8tc qdisc show dev <interface>
 9
10返回:
11qdisc mq 0: root 
12qdisc fq_codel 0: parent :2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64 
13qdisc fq_codel 0: parent :1 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64 
14
15# 替换qdisc
16tc qdisc replace dev <interface> <position> <qdisc-type> [parameters]

参数说明:

  • <interface>:网络接口名,如eth0、enp0s3等
  • <position>:位置,通常是root(根队列)
  • <qdisc-type>:队列类型,如netem、tbf等

网络延迟模拟

固定延迟

1# 添加2ms的固定延迟
2tc qdisc add dev eth0 root netem delay 2ms
3
4# 查看当前配置
5tc qdisc show dev eth0

变动延迟

1# 添加100ms±10ms的变动延迟(正态分布)
2tc qdisc add dev eth0 root netem delay 100ms 10ms
3
4# 添加100ms±10ms的变动延迟,25%相关性
5tc qdisc add dev eth0 root netem delay 100ms 10ms 25%

延迟分布

1# 使用uniform分布
2tc qdisc add dev eth0 root netem delay 100ms 20ms distribution uniform
3
4# 使用normal分布(默认)
5tc qdisc add dev eth0 root netem delay 100ms 20ms distribution normal
6
7# 使用pareto分布
8tc qdisc add dev eth0 root netem delay 100ms 20ms distribution pareto

丢包模拟

随机丢包

1# 1%的随机丢包率
2tc qdisc add dev eth0 root netem loss 1%
3
4# 0.1%的随机丢包率
5tc qdisc add dev eth0 root netem loss 0.1%
6
7# 5%丢包,25%相关性
8tc qdisc add dev eth0 root netem loss 5% 25%

连续丢包

1# Gilbert模型:p=丢包概率,r=恢复概率,1-h=好状态时丢包概率,1-k=坏状态时不丢包概率
2tc qdisc add dev eth0 root netem loss gemodel 1% 10% 70% 0.1%

包重排模拟

1# 25%的包会被延迟,延迟时间为10ms,相关性50%
2tc qdisc add dev eth0 root netem delay 10ms reorder 25% 50%
3
4# 1%的包立即发送(跳过队列)
5tc qdisc add dev eth0 root netem gap 5 delay 10ms

包重复

1# 1%的包会被重复发送
2tc qdisc add dev eth0 root netem duplicate 1%

包损坏

1# 0.1%的包会被损坏(随机位翻转)
2tc qdisc add dev eth0 root netem corrupt 0.1%

带宽限制

使用TBF(Token Bucket Filter)

1# 限制带宽为1Mbit/s,突发为32KB,延迟为400ms
2tc qdisc add dev eth0 root tbf rate 1mbit latency 400ms burst 32kbit
3
4# 限制带宽为200kbit/s
5tc qdisc add dev eth0 root tbf rate 200kbit latency 10ms burst 1600

使用HTB(Hierarchy Token Bucket)

 1# 创建HTB根队列
 2tc qdisc add dev eth0 root handle 1: htb default 30
 3
 4# 创建根类,总带宽6Mbit/s
 5tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k
 6
 7# 创建子类,保证带宽5Mbit/s,最大6Mbit/s
 8tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k
 9tc class add dev eth0 parent 1:1 classid 1:20 htb rate 1mbit ceil 6mbit burst 15k
10tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1mbit ceil 6mbit burst 15k

复合条件模拟

延迟+丢包

1# 100ms延迟 + 1%丢包
2tc qdisc add dev eth0 root netem delay 100ms loss 1%

延迟+丢包+重排

1# 100ms延迟 + 1%丢包 + 10%重排
2tc qdisc add dev eth0 root netem delay 100ms loss 1% reorder 10%

延迟+带宽限制

1# 先添加netem进行延迟
2tc qdisc add dev eth0 root handle 1: netem delay 100ms
3
4# 在netem下添加tbf进行带宽限制
5tc qdisc add dev eth0 parent 1:1 handle 10: tbf rate 256kbit buffer 1600 limit 3000

针对特定流量的控制

使用filter进行分类

 1# 创建HTB根队列
 2tc qdisc add dev eth0 root handle 1: htb
 3
 4# 创建类
 5tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
 6tc class add dev eth0 parent 1: classid 1:2 htb rate 1mbit
 7
 8# 添加过滤器:目标端口80的流量走1:1类
 9tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
10    match ip dport 80 0xffff flowid 1:1
11
12# 添加过滤器:目标IP 192.168.1.100的流量走1:2类  
13tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
14    match ip dst 192.168.1.100 flowid 1:2

针对特定IP限速

 1# 创建HTB队列
 2tc qdisc add dev eth0 root handle 1: htb
 3
 4# 创建默认类(无限制)
 5tc class add dev eth0 parent 1: classid 1:1 htb rate 1000mbit
 6
 7# 创建限制类(1Mbit/s)
 8tc class add dev eth0 parent 1: classid 1:2 htb rate 1mbit ceil 1mbit
 9
10# 过滤特定IP的流量
11tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
12    match ip src 192.168.1.100 flowid 1:2

Docker环境下的TC使用

容器网络接口

1# 查看docker容器的网络接口
2docker exec <container_id> ip addr
3
4# 在宿主机上对容器的veth接口进行限制
5# 假设容器的veth接口是vethxxxx
6tc qdisc add dev vethxxxx root netem delay 100ms

容器内部使用TC

1# 需要特权模式运行容器
2docker run --privileged -it ubuntu:20.04 /bin/bash
3
4# 在容器内部使用tc
5tc qdisc add dev eth0 root netem delay 50ms loss 1%

查看和管理

查看当前qdisc状态

 1# 查看所有接口的qdisc
 2tc qdisc show
 3
 4# 查看特定接口
 5tc qdisc show dev eth0
 6
 7# 查看详细统计信息
 8tc -s qdisc show dev eth0
 9
10# 查看类信息
11tc class show dev eth0
12
13# 查看过滤器
14tc filter show dev eth0

删除qdisc

1# 删除eth0上的根qdisc(会清除所有TC规则)
2tc qdisc del dev eth0 root
3
4# 删除特定handle的qdisc
5tc qdisc del dev eth0 handle 10:

替换qdisc配置

1# 替换现有配置
2tc qdisc replace dev eth0 root netem delay 200ms loss 2%

实际应用场景

网络测试

1# 模拟慢速网络环境测试应用性能
2tc qdisc add dev eth0 root netem delay 200ms loss 1%
3
4# 测试完成后清除规则
5tc qdisc del dev eth0 root

带宽管理

 1# 为不同服务分配带宽
 2tc qdisc add dev eth0 root handle 1: htb default 30
 3
 4# Web服务保证2Mbit/s
 5tc class add dev eth0 parent 1: classid 1:10 htb rate 2mbit ceil 4mbit
 6tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
 7    match ip sport 80 0xffff flowid 1:10
 8
 9# 文件传输限制在1Mbit/s  
10tc class add dev eth0 parent 1: classid 1:20 htb rate 1mbit ceil 1mbit
11tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
12    match ip sport 21 0xffff flowid 1:20

QoS配置

 1# 优先级队列,3个级别
 2tc qdisc add dev eth0 root handle 1: prio
 3
 4# 高优先级:VoIP流量
 5tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
 6    match ip dport 5060 0xffff flowid 1:1
 7
 8# 中优先级:HTTP流量  
 9tc filter add dev eth0 parent 1: protocol ip prio 2 u32 \
10    match ip dport 80 0xffff flowid 1:2
11
12# 低优先级:其他流量(默认)
13# flowid 1:3 是默认队列

高级用法

使用fq_codel

1# 使用Fair Queueing CoDel算法,减少缓冲膨胀
2tc qdisc add dev eth0 root fq_codel

使用cake

1# 使用CAKE(Common Applications Kept Enhanced)算法
2tc qdisc add dev eth0 root cake bandwidth 100mbit

基于mark的分类

1# 在iptables中给包打标记
2iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 1
3iptables -t mangle -A OUTPUT -p tcp --dport 443 -j MARK --set-mark 2
4
5# 基于mark进行分类
6tc filter add dev eth0 parent 1: protocol ip prio 1 handle 1 fw flowid 1:1
7tc filter add dev eth0 parent 1: protocol ip prio 1 handle 2 fw flowid 1:2

故障排查

常见问题

  1. qdisc添加失败

    1# 检查内核模块是否加载
    2lsmod | grep sch_netem
    3
    4# 手动加载模块
    5modprobe sch_netem
    
  2. 配置不生效

    1# 检查接口状态
    2ip link show eth0
    3
    4# 查看详细错误信息
    5tc -d qdisc show dev eth0
    
  3. 性能问题

    1# 查看统计信息,检查dropped包数量
    2tc -s qdisc show dev eth0
    3
    4# 检查系统负载
    5top
    6sar -n DEV 1
    

调试技巧

1# 开启详细输出
2tc -d qdisc add dev eth0 root netem delay 100ms
3
4# 查看内核消息
5dmesg | grep -i "tc\|qdisc"
6
7# 使用tcpdump验证效果
8tcpdump -i eth0 -n host <target_ip>

注意事项

  1. 权限要求:TC命令需要root权限或CAP_NET_ADMIN能力
  2. 性能影响:复杂的TC规则会消耗CPU资源,在高流量环境下需要注意
  3. 内核支持:某些高级功能需要特定的内核版本支持
  4. 网络接口状态:只能在UP状态的网络接口上应用TC规则
  5. 规则清理:系统重启后TC规则会丢失,需要在启动脚本中重新配置

参考资料