菜鸟科技网

tc命令详解

tctraffic control(流量控制)的缩写,它是 Linux 内核中 Netfilter网络队列 discipline (qdisc) 框架下的一个命令行工具,它的功能远不止限速,而是一个复杂的网络流量整形和管理的“瑞士军刀”。

tc命令详解-图1
(图片来源网络,侵删)

tc 是什么?为什么需要它?

想象一下,你家里的网络带宽是一条高速公路,你的所有网络应用(网页、下载、视频、游戏)都在这条路上行驶。

  • 没有 tc 的情况:所有应用都“自由竞争”车道,如果你的电脑正在用迅雷下载一个大文件(一个“重型卡车”),它可能会占满整条路,导致你看视频(一辆“小轿车”)卡顿,或者玩游戏(一辆“救护车”)延迟极高。
  • 使用 tc 的情况:你可以扮演“交通警察”,用 tc 来制定交通规则。
    • 限速:规定迅雷下载不能超过 10MB/s。
    • 保证带宽:保证视频通话始终有 1MB/s 的专用带宽,不受其他应用影响。
    • 优先级:让游戏数据包(如 UDP)拥有最高优先级,即使网络拥堵,它也能优先通过。
    • 延迟控制:降低关键应用的网络延迟。
    • 丢包控制:在拥塞时,优先丢弃不重要的数据包(如旧网页数据),而不是重要的实时数据。

tc 就是实现这些“交通规则”的核心工具。


核心概念:理解 tc 的工作原理

要掌握 tc,必须先理解它的几个核心组件,它们之间是层层嵌套的关系。

qdisc (Queueing Discipline) - 队列规则

这是 tc 的最核心概念。qdisc 是附加在网络接口(如 eth0, wlan0)上的一个排队规则,所有从接口发出的数据包,都必须先经过这个 qdisc 的“队列”进行处理,然后再发送出去。

tc命令详解-图2
(图片来源网络,侵删)

Linux 内核默认的 qdisc 是 pfifo_fast(一个先进先出的快速队列),我们通常用 tc 来替换或修改它。

常见的 qdisc 类型:

  • pfifo / bfifo (First-In, First-Out / Byte-In, First-Out):最简单的队列,先进先出。bfifo 按字节计算队列大小。
  • pfifo_fast:默认 qdisc,基于三个优先级队列的先进先出,内核网络包会根据 TOS (Type of Service) 字段被分类到不同队列。
  • htb (Hierarchical Token Bucket)非常重要且常用,分层令牌桶模型,可以实现复杂的分层带宽保证和限速,就像一个公司的组织架构,可以为不同部门(类)分配不同的预算(带宽)。
  • cbq (Class Based Queueing):比 HTB 更老但功能强大的分类队列,同样可以实现分层带宽管理。
  • sfq (Stochastic Fairness Queueing):随机公平队列,旨在让数据流之间公平地共享带宽,防止某个“大象流”(大文件传输)霸占所有带宽。
  • tbf (Token Bucket Filter):令牌桶过滤器,非常简单,只做一件事:以恒定的速率发送数据包,可以用来做简单的限速。
  • netem (Network Emulator):网络模拟器,主要用于测试,可以模拟网络延迟、丢包、乱序、重复等真实网络环境中的问题。

class (Class) - 类

当使用像 htbcbq 这样的分层 qdisc 时,我们可以在 qdisc 内部创建多个 class,每个 class 可以有自己的带宽限制、优先级和子 qdisc,这构成了一个“类树”,是实现精细化管理的基础。

htb qdisc 下:

  • 根类 (root class)
    • 类1: 保证带宽 10Mbps,优先级高
      • 子 qdisc: sfq
    • 类2: 保证带宽 5Mbps,优先级低
      • 子 qdisc: pfifo

filter (过滤器)

数据包到达接口后,需要被分类到某个 class 中。filter 就是做这件事的规则。tc 提供了多种匹配条件来判断一个数据包应该去哪个 class。

常见的 filter 类型:

  • u32:最强大、最灵活的过滤器,可以根据数据包头(IP地址、端口、协议等)的任意比特位进行匹配。
  • fw:基于 iptablesmark,先通过 iptables 给数据包打上标记(mark),tc filter 根据 mark 进行分类,这是非常实用的方法。
  • route:基于路由表进行分类,可以根据数据包的目的 IP 地址所在的网络路由进行分类。
  • cgroup:基于 cgroup 分类,可以根据进程所属的 cgroup 来分类数据包,非常适合为特定应用(如 Docker 容器)设置流量策略。

tc 命令基本语法

tc 的命令结构非常清晰,遵循一个固定的模式:

tc [ OPTIONS ] OBJECT { COMMAND | help }
  • OBJECT: 操作对象,可以是 qdisc, class, filter
  • COMMAND: 具体操作,如 add, del, change, show
  • 常用 OPTIONS:
    • -s (--stats): 显示详细的统计信息,如包数、字节、延迟等。
    • -d (--details): 显示更详细的信息。
    • -g (--gov): 显示类树结构。

实战案例:从简单到复杂

我们假设目标网络接口是 eth0

案例 1:简单的全局限速 (使用 tbf)

目标:限制 eth0 的总出站带宽不超过 1Mbps (即 1024 kbit/s)。

# 1. 添加一个 tbf qdisc 到 eth0 的根
#   root: 添加到根
#   handle 1: 给这个 qdisc 一个句柄 1
#   dev eth0: 作用于 eth0 设备
#   rate 1mbit: 平均速率 1Mbps
#   burst 32kbit: 突发流量大小,通常设置为速率的几十分之一
tc qdisc add dev eth0 root handle 1: tbf rate 1mbit burst 32kbit latency 400ms
# 2. 查看规则
tc -s qdisc show dev eth0

解释

  • tbf 会以 rate 设定的速率匀速地发送数据包。
  • burst 允许在短时间内以高于 rate 的速度发送数据,用于处理突发流量。
  • latency 是一个延迟参数,tbf 会尽力保证数据包的延迟不超过这个值。

案例 2:为特定 IP 保证带宽 (使用 htb + u32)

目标:局域网内 IP 为 168.1.100 的电脑保证有 2Mbps 的带宽,其余设备共享剩下的带宽。

# 1. 首先删除 eth0 上可能存在的旧规则
tc qdisc del dev eth0 root
# 2. 添加一个 HTB qdisc 作为根
tc qdisc add dev eth0 root handle 1: htb default 30
# 3. 创建一个根类 (class 1:1),总带宽上限为 10Mbps
tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit
# 4. 创建一个子类 (class 1:10),专门给 192.168.1.100 保证 2Mbps
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 2mbit ceil 2mbit
# 5. 创建过滤器,将来自 192.168.1.100 的数据包分类到 1:10 类
#   protocol ip: 只匹配 IP 包
#   u32: 使用 u32 过滤器
#   match ip dst 192.168.1.100: 匹配目的 IP
#   flowid 1:10: 匹配成功后,流入类 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 0 u32 match ip dst 192.168.1.100 flowid 1:10
# 6. 创建一个默认类 (class 1:30),其余流量共享剩下的带宽
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 8mbit ceil 10mbit
# 7. 查看类树结构
tc -s class show dev eth0
tc -s filter show dev eth0

解释

  • htb 需要先创建一个 root class (1:1),它定义了总带宽池。
  • 然后在这个池下创建子类 (1:10 和 1:30)。
  • rate 是保证带宽,ceil (ceiling) 是最大带宽,在 1:10 中,我们保证 2Mbps,也限制它最多用 2Mbps,在 1:30 中,保证 8Mbps,但最多可以抢占到 10Mbps。
  • filter 负责将数据包“路由”到正确的类中。

案例 3:为应用限速 (使用 iptables + tc)

目标:限制 Transmission 下载工具的带宽不超过 500KB/s (即 4mbit/s)。

这种方法更优雅,因为它不关心 IP,只关心进程。

# 1. 给 Transmission 的流量打上防火墙标记 (mark)
#   --set-mark 1: 将匹配的数据包标记为 1
#   -m owner --pid-owner $(pgrep transmission): 匹配 transmission 进程的 PID
#   -j MARK: 执行 MARK 动作
# 注意:需要先安装 iptables
iptables -t mangle -A OUTPUT -m owner --pid-owner $(pgrep transmission) -j MARK --set-mark 1
# 2. 添加一个 HTB qdisc
tc qdisc add dev eth0 root handle 1: htb default 20
# 3. 创建根类
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
# 4. 创建一个用于标记流量的类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 4mbit ceil 4mbit
# 5. 创建过滤器,根据防火墙标记来分类
#   protocol ip: 匹配 IP 包
#   handle 1: 匹配标记为 1 的数据包
tc filter add dev eth0 protocol ip parent 1:0 prio 0 handle 1 fw flowid 1:10
# 6. 创建一个默认类,让其他流量正常通过
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 100mbit
# 7. 查看
tc -s qdisc show dev eth0
tc -s filter show dev eth0

解释

  • iptablesmangle 表和 MARK 目标用于给数据包“盖章”。
  • tc filterfw 类型会读取这个 mark,并根据它进行分类。
  • 这种方法的优点是即使 Transmission 连接了不同的 IP 地址,限速规则依然有效。

tc 的常见问题与注意事项

  1. 作用范围tc 默认只控制出站流量 (egress),如果要控制入站流量 (ingress),需要先启用 ingress qdisc。

    tc qdisc add dev eth0 handle ffff: ingress

    入站控制通常用于限制下载流量,但配置更复杂,且需要配合 tc filteru32 匹配数据包的源 IP 等。

  2. 单位tc 中的速率单位通常是 kbit (千比特) 或 mbit (兆比特),注意与 KB/s (千字节/秒) 的区别。1MB/s = 8mbit/s

  3. 规则的持久性tc 的规则在重启后会丢失,如果需要永久生效,可以编写一个 systemd 服务或在网络启动脚本(如 /etc/network/interfaces 或 NetworkManager 的 dispatcher)中执行 tc 命令。

  4. 复杂性tc 功能强大,但配置复杂,一个错误的规则可能导致网络中断。强烈建议在测试环境或非生产时间进行操作

  5. 监控:使用 tc -s [qdisc|class|filter] show dev <interface> 来监控规则的效果和统计信息,这对于调试至关重要。


tc 是 Linux 网络管理中一个极其强大且底层的工具,它通过 qdiscclassfilter 三个核心组件,提供了对网络流量的精细控制能力。

  • 入门:从简单的 tbf 全局限速开始。
  • 进阶:学习使用 htbu32 为特定 IP 或端口进行分类和限速。
  • 高级:结合 iptablesmark 功能,为特定应用设置策略。

掌握 tc 意味着你从一个普通用户变成了网络管理员,能够深度定制和优化你的网络环境,解决各种复杂的网络性能问题,虽然学习曲线陡峭,但其带来的回报也是巨大的。

分享:
扫描分享到社交APP
上一篇
下一篇