第9章 流量控制与QoS
学习目标
- 理解qdisc(队列规则)的工作原理
- 掌握TC(Traffic Control)工具的使用
- 了解HTB、fq_codel等调度算法
- 能够配置和调优网络QoS
🔬 原理
qdisc(队列规则)
qdisc类型:
- pfifo_fast:默认,3个优先级队列
- fq_codel:公平队列,主动队列管理
- HTB:分层令牌桶,复杂带宽分配
- TBF:令牌桶过滤器,简单限速
HTB(Hierarchical Token Bucket)
HTB特点:
- 分层限速
- 带宽借用
- 优先级控制
HTB结构:
root (100Mbps)
├── class1:1 (50Mbps)
│ ├── class1:10 (30Mbps)
│ └── class1:20 (20Mbps)
└── class1:2 (50Mbps)
fq_codel算法
fq_codel特点:
- 按流隔离
- 主动队列管理
- 控制延迟
算法原理:
- 按流哈希分组
- 轮询调度各流
- 检测队列延迟
- 主动丢弃包
️ 实现
qdisc实现
struct Qdisc {
struct Qdisc_ops *ops;
struct net_device *dev;
struct sk_buff_head q;
struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats;
unsigned long state;
struct sk_buff *gso_skb;
u32 handle;
u32 parent;
int (*enqueue)(struct sk_buff *skb, struct Qdisc *sch);
struct sk_buff *(*dequeue)(struct Qdisc *sch);
// ... 更多字段
};
HTB实现
struct htb_class {
struct Qdisc_class_common common;
struct psched_ratecfg rate;
struct psched_ratecfg ceil;
s64 buffer, cbuffer;
s64 mbuffer;
struct htb_class *parent;
struct htb_class *inner;
struct htb_class *leaf;
struct Qdisc *q;
struct tcf_proto *filter_list;
struct htb_class *next;
// ... 更多字段
};
🛠️ 命令
TC命令
# 查看qdisc
tc qdisc show dev eth0
# 添加qdisc
sudo tc qdisc add dev eth0 root htb default 12
# 删除qdisc
sudo tc qdisc del dev eth0 root
# 查看class
tc class show dev eth0
# 添加class
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
限速配置
# TBF限速
sudo tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms
# HTB限速
sudo tc qdisc add dev eth0 root handle 1: htb default 12
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 50mbit ceil 100mbit
代码
简单限速程序
// simple_tc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
return 1;
}
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr.s_addr = INADDR_ANY
};
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
close(sock);
return 1;
}
if (listen(sock, 128) < 0) {
perror("listen");
close(sock);
return 1;
}
printf("Server listening on port 8080\n");
while (1) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_len);
if (client_sock < 0) {
perror("accept");
continue;
}
// 简单限速:每次发送1KB,间隔1ms
char buffer[1024];
memset(buffer, 'A', sizeof(buffer));
for (int i = 0; i < 1000; i++) {
if (send(client_sock, buffer, sizeof(buffer), 0) < 0) {
perror("send");
break;
}
usleep(1000); // 1ms延迟
}
close(client_sock);
}
close(sock);
return 0;
}
编译运行:
gcc simple_tc.c -o simple_tc
./simple_tc
🧪 实验
实验1:TBF限速测试
目标:测试TBF限速效果
步骤:
# 1. 查看当前qdisc
tc qdisc show dev eth0
# 2. 添加TBF限速
sudo tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms
# 3. 测试限速效果
iperf3 -s &
iperf3 -c localhost -t 30
# 4. 删除限速
sudo tc qdisc del dev eth0 root
# 5. 对比测试
iperf3 -c localhost -t 30
预期结果:
- 理解TBF限速原理
- 观察限速效果
- 掌握TBF配置
实验2:HTB分层限速
目标:配置HTB分层限速
步骤:
# 1. 添加HTB qdisc
sudo tc qdisc add dev eth0 root handle 1: htb default 12
# 2. 添加根class
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
# 3. 添加子class
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 50mbit ceil 100mbit
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 30mbit ceil 50mbit
# 4. 添加过滤器
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 80 0xffff flowid 1:10
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dport 443 0xffff flowid 1:20
# 5. 测试效果
iperf3 -s -p 80 &
iperf3 -s -p 443 &
iperf3 -c localhost -p 80 -t 30
iperf3 -c localhost -p 443 -t 30
预期结果:
- 理解HTB分层结构
- 观察带宽分配
- 掌握HTB配置
实验3:fq_codel测试
目标:测试fq_codel公平队列
步骤:
# 1. 添加fq_codel qdisc
sudo tc qdisc add dev eth0 root fq_codel
# 2. 测试多流公平性
for i in {1..5}; do
iperf3 -c localhost -t 30 &
done
wait
# 3. 查看统计信息
tc -s qdisc show dev eth0
预期结果:
- 理解fq_codel算法
- 观察公平性
- 掌握fq_codel配置
排错
常见问题排查
问题1:qdisc不生效
# 检查qdisc配置
tc qdisc show dev eth0
# 检查class配置
tc class show dev eth0
# 检查过滤器
tc filter show dev eth0
问题2:限速不准确
# 检查限速参数
tc class show dev eth0
# 调整限速参数
sudo tc class change dev eth0 parent 1:1 classid 1:10 htb rate 50mbit ceil 100mbit
# 测试限速效果
iperf3 -c localhost -t 30
问题3:性能问题
# 检查qdisc统计
tc -s qdisc show dev eth0
# 检查丢包情况
tc -s class show dev eth0
# 优化qdisc参数
sudo tc qdisc change dev eth0 root fq_codel limit 1000
排错清单
- [ ] 检查qdisc配置(tc qdisc show)
- [ ] 验证class配置(tc class show)
- [ ] 确认过滤器规则(tc filter show)
- [ ] 测试限速效果(iperf3、netperf)
- [ ] 查看统计信息(tc -s)
- [ ] 检查网络连通性(ping、telnet)
- [ ] 查看系统日志(dmesg、/var/log/syslog)