iptables方案

这个方案纯基于iptables,不需要内核模块,对容器更加友好一些。

iptables -A OUTPUT -d xx.xx.xx.xx -m statistic --mode random --probability 0.1 -j DROP

但是这个方案有个副作用。ping的时候,能看到错误“不允许的操作”。

tc方案

tc方案相对比较复杂。我们先不说这些复杂的事情,先说结果。

tc qd add dev wlan0 root netem delay 100ms
tc qd change dev wlan0 root netem loss 50%

一个是延迟一个是丢包,一个是设定一个是修改。netem还允许你做乱序和重复。方法就不细写了。删除是这么干。

tc qd del dev wlan0 root netem

你再用tc qd show看看是不是规则已经没了?

tc简述

tc是linux下面用来控制网络发包(注意是发包)的一套系统。基本的设计目标是确定优先级,限流,也有测试性的丢包之类的策略。可以配合iptables和route协同工作。

基本原理

包从进入tc开始,分为多个qd(qdisc)。每个qd可以包含多个子qd,qd彼此连接形成一颗树。每个qd上可以附加filter,选择进入哪个child。如果都没命中,那就看本身规则。

我们先从最简单的例子开始。将root qd改为prio。

sudo tc qdisc add dev eth0 root handle 1: prio

使用tc qd show查看变化。完成后使用sudo tc qdisc del dev eth root删除变化,还原为默认的pfifo_fast。

使用filter来分类

要分类,最低是两类。一类父,一类子。具体进入哪个sub-class可以用filter来设定。filter可以用sudo tc filter show dev eth0来查看。注意,这里必须附加dev。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1s loss 2%
sudo tc filter del dev eth0
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.1 flowid 1:1

完成后,192.168.33.1被延迟,192.168.33.2无效果。

注意prio的默认bands是3,因此直接插入parent 1:4会报错。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:3 handle 30: netem delay 1s loss 2%
sudo tc qdisc add dev eth0 parent 1:4 handle 40: sfq

将bands改为5问题消失。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio bands 5
sudo tc qdisc add dev eth0 parent 1:3 handle 30: netem delay 1s loss 2%
sudo tc qdisc add dev eth0 parent 1:4 handle 40: sfq

将flowid更换为classid将会导致不起作用。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1s loss 2%
sudo tc filter del dev eth0
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.1 flowid 20:

此时ping 192.168.33.1,结果没有延迟。

多个sub-class的例子

更复杂的例子。在prio下面分了多个sub-class。命中IP的进入延迟,未命中IP的按照prio的规则走。在prio里,使用priomap将prio映射到不同的sub-class。测试下来,ICMP报文的默认规则将是1:2。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1s loss 2%
sudo tc qdisc add dev eth0 parent 1:2 handle 20: netem delay 2s loss 2%
sudo tc qdisc add dev eth0 parent 1:3 handle 30: netem delay 3s loss 2%
sudo tc filter del dev eth0
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.1 flowid 1:1
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.2 flowid 1:2
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.3 flowid 1:3

测试ping 192.168.33.4,结果是延迟2s。

tc+filter方案

运用’多个sub-class的例子’的同类方法可以用于将特定IP延迟丢包,其他走默认的pfifo_fast。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1s loss 2%
sudo tc qdisc add dev eth0 parent 1:2 handle 20: pfifo_fast
sudo tc filter del dev eth0
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.1 flowid 1:1
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst 192.168.33.2 flowid 1:1

tc+iptables方案

我们也可以不用内置的u32 filter来做流量分离,而是先用iptables做mark,然后根据mark来做流量分离。

sudo tc qdisc del dev eth0 root
sudo tc qdisc add dev eth0 root handle 1: prio
sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1s
sudo tc qdisc add dev eth0 parent 1:3 handle 30: netem delay 2s
sudo tc filter del dev eth0
sudo tc filter add dev eth0 parent 1:0 prio 1 protocol ip handle 5 fw flowid 1:1
sudo tc filter add dev eth0 parent 1:0 prio 0 protocol ip handle 6 fw flowid 1:3
sudo iptables -F OUTPUT -t mangle
sudo iptables -A OUTPUT -t mangle -p icmp -d 192.168.33.1 -j MARK --set-mark 5
sudo iptables -A OUTPUT -t mangle -p icmp -d 192.168.33.2 -j MARK --set-mark 6

这个方案和filter方案没有什么本质性区别,但是使用iptables完成,个人觉得更加灵活一些。

清除和持久化

刚刚把脚本全部跑了的同学,别忘了执行一下语句清理环境。不然残留各种垃圾配置的话,上网的时候会很慢哦。

sudo iptables -F OUTPUT -t mangle
sudo tc filter del dev eth0
sudo tc qdisc del dev eth0 root

如果希望效果持久,可以将语句添加到rc.local里。但是实话说,我还没见过谁希望自己的系统一开机就变慢呢。QoS倒是有可能。

参考

  1. 网络模拟:丢包,延迟,乱序
  2. linux 下使用 tc 模拟网络延迟和丢包
  3. Linux 高级流控