Linux 流量控制:如何使用网桥和 qdisc 确定流量的优先级?

Linux 流量控制:如何使用网桥和 qdisc 确定流量的优先级?

我正在尝试通过网络中基于 Linux 的软件桥对流量进行优先级排序。当我在本地(在托管桥的机器上)生成流量时,流量的优先级正确。但是,“远程”流量(来自通过桥的其他节点)没有优先级(向所有发送者分配相同的带宽)。也许有人知道为什么?

针对 I350 网络适配器 (Linux 5.1.8-1-MANJARO #1 SMP PREEMPT Sun Jun 9 20:44:14 UTC 2019 x86_64 GNU/Linux),桥接设置如下:

brctl addbr br0
ip link set dev enp1s0f0 promisc on
ip link set dev enp1s0f1 promisc on
ip link set dev enp1s0f2 promisc on
ip link set dev enp1s0f3 promisc on

brctl addif br0 enp1s0f0
brctl addif br0 enp1s0f1
brctl addif br0 enp1s0f2
brctl addif br0 enp1s0f3

ip link set dev br0 up

tc qdisc del dev enp1s0f0  root
tc qdisc add dev enp1s0f0  root prio
tc qdisc del dev enp1s0f1  root
tc qdisc add dev enp1s0f1  root prio
tc qdisc del dev enp1s0f2  root
tc qdisc add dev enp1s0f2  root prio
tc qdisc del dev enp1s0f3  root
tc qdisc add dev enp1s0f3  root prio

ip addr add 192.168.1.1/24 dev br0

UDP 流量由 iperf3 生成,并通过适当设置 TOS 字段,例如

Low-Prio Sender: iperf3 -c 192.168.1.140 -u -b 100m -S 0x2 -p 5201 -t 30
Hi-Prio Sender : iperf3 -c 192.168.1.140 -u -b 100m -S 0x0 -p 5202 -t 30

Prio map 保留默认设置: priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

如果我明确地对流量进行分类,则优先级对远程流量有效:

tc filter add dev enp1s0f1 parent 1: protocol ip prio 10 u32 match ip dst 192.168.1.140 match ip dport 5201 0xffff flowid 1:1
tc filter add dev enp1s0f1 parent 1: protocol ip prio 20 u32 match ip dst 192.168.1.140 match ip dport 5202 0xffff flowid 1:2

但不是默认设置....也许是第 2 层/第 3 层的问题?

答案1

我再次回到这个话题,因为我在桥接器端口上实现 qdisc 时遇到了同样的麻烦。

第一个使用 tc filter 的解决方案对我来说不起作用。arp 解决方案似乎是一个不错的解决方案,但在使用 DHCP 时会出现问题,因为它会通过 OSI 模型的第 2 层,而 arp bridge 会通过第 3 层(我看到可以使用 dhcp-helper 来解决这个问题,但我不想使用它)。

因此我在我的嵌入式 Linux 系统中找到了另一个适合我的解决方案。

我创建了第二个带有 VLAN 接口的网桥:

我有第一个桥 br0,它与 eth0、eth1 和 eth2 建立连接。

同时,我有第二个网桥 br1,它连接 eth0.100、eth1.100 和 eth2.100。

使用这种方法,我的以太网帧由 VLAN id 为 100 的 VLAN 标签组成,并通过 br1 传递,因此 PCP 用于映射数据包的优先级。当我使用以下命令查看我的 qdisc 类时tc -s -d qdisc ls dev eth0,我发现它解决了这个问题并且我的 qdisc 现在可以使用优先级来调整我的流量。

希望这个解决方案可以帮助某人

答案2

我读了桥接和 prio 队列调度程序的源代码。我得到了一些结果:

  • prio qdisc 使用该skb->priority字段通过 priomap 对数据包进行分类。
  • 默认情况下,skb-priorityL2 传输帧不会填充该字段。
  • 因此正确的方法是向每个桥接端口添加分类器,以根据 ToS/DSCP 字段对帧进行分类。
  • 默认情况下,priomap 看起来像1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
  • 可以使用分类器完成 ToS 和队列带之间的相同映射(根 qdisc 的句柄是1:0,因此子类将具有范围为 的 classid 1:11:3
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x00 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x02 classid 1:3
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x04 classid 1:3
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x06 classid 1:3
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x08 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x0a classid 1:3
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x0c classid 1:1
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x0e classid 1:1
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x10 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x12 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x14 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x16 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x18 classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x1a classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x1c classid 1:2
tc filter add dev eth0 parent 1: protocol ip flower ip_tos 0x1e classid 1:2

答案3

与此同时,我已经设法找到了解决方案:)

Linux 桥接器(brctl)作为第 2 层设备工作。

TOS 标记是 IEEE P802.1p(属于 IEEE_802.1Q)的一部分,属于 IP 报头(https://en.wikipedia.org/wiki/IEEE_802.1Q

由于 Linux 桥接在第 2 层工作,因此它似乎忽略了此字段。(但是,根据 OSI 模型https://en.wikipedia.org/wiki/OSI_model 802.1Q 属于第 2 层)因此,所有数据包都被定向到同一个 qdisc 类(在我的设置类 1:2 中)我使用以下命令弄清楚了:

tc -s -s -d c ls dev enp1s0f1  

它允许您在运行时观察不同 qdisc 类的队列后来,我的“远程”流量被安排为来自 1:2 类的流量与其他流(例如,来自托管网桥的机器的“本地”流)一起,这导致了一些用例的正确结果.....所以要小心!;)

对我有用的是使用代理 ARP 桥接网络连接(即强制第 3 层,https://wiki.debian.org/BridgeNetworkConnectionsProxyArp

首先激活IP转发和代理arp

echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
echo 1 > /proc/sys/net/ipv4/ip_forward

然后向您的节点添加路由:

ip ro add <node IP>/32 dev <local interface>

例子:

    ip ro add 192.168.1.12/32 dev enp1s0f0

相关内容