我希望能够帮助您了解网桥中流量过滤的工作原理,特别是对于源自本地的数据包/以太网帧。为了解释这个问题,我将简短地描述一下情况、目标、到目前为止我所采取的步骤以及我失败的地方。
情况
在 Linux 主机 (debian buster x64) 上,我有一个运行 Windows Server 2019 的虚拟机 (Qemu / KVM)。由于某些原因,我需要对所有网络流量进行速率限制进入那个虚拟机来自主机以外的所有来源(即来自其他物理机器)。相比之下,所有网络流量源自主机本身并转到该虚拟机应该不是受到速率限制。
Windows本身提供了QoS机制,但它们要么仅适用于出站流量,要么不适合解决该问题。因此,我决定尝试在主机端实现限速。
VM通过网桥连接到主机网络:
root@cerberus /var/log # brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.002590fb7105 no enp1s0f1
garak0
garak0
,第二个桥接端口,是VM的虚拟网络适配器;enp1s0f1
,第一个桥接端口,是物理网络适配器。enp1s0f1
是该主机上唯一连接到外部的物理网络适配器;也就是说,来自其他计算机的该主机的任何流量都通过 进入enp1s0f1
。
MAC 地址如下(省略不相关的行和一堆此处不感兴趣的接口):
root@cerberus /var/log # ifconfig -a
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.20.10 netmask 255.255.255.0 broadcast 192.168.20.255
ether 00:25:90:fb:71:05 txqueuelen 1000 (Ethernet)
...
enp1s0f1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:25:90:fb:71:05 txqueuelen 1000 (Ethernet)
...
garak0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether b6:89:d8:4e:fa:2c txqueuelen 1000 (Ethernet)
...
VM 虚拟网卡另一端的 MAC 地址(即 VM 中的 O/S 实际看到的 MAC 地址,位于连接到 VM 的计算机的 arp 缓存中)02:01:01:01:16:01
。
目标
使用 nftables,我想通过过滤第 2 层的网桥流量来对进入虚拟机的流量进行速率限制,请记住,该限制必须仅适用于来自主机外部的流量,并且不得对来自主机的流量应用任何限制。将自身托管到虚拟机。
我快到了,但我正在与一个细节作斗争,这使得演出停止了(见下文)。
我所做的和有效的
昨天我学习了 nftables 的一些概念(这是我第一次接触它)并创建了以下规则集:
root@cerberus /var/log # nft list ruleset
table bridge filter1 {
chain test {
type filter hook forward priority 0; policy accept;
ether daddr 02:01:01:01:16:01 limit rate over 10 mbytes/second drop
}
}
这是一个陡峭的学习曲线,主要是因为我看到的所有示例要么仅显示如何创建规则,而不显示表和链,要么使用输入钩子,这ether daddr
显然不起作用。
无论如何,这确实有效,因为它确实将到达 VM 的流量速率平均限制为 10 MB/s。
什么不起作用/我的实际问题
根据上面显示的规则集,全部到虚拟机的流量受到速率限制,包括来自主机本身的流量。我试图通过改变规则集来纠正这个问题:
root@cerberus /var/log # nft list ruleset
table bridge filter1 {
chain test {
type filter hook forward priority 0; policy accept;
ether daddr 02:01:01:01:16:01 ether saddr 00:25:90:fb:71:05 limit rate over 10 mbytes/second drop
}
}
尽管我已经有所怀疑,但当我看到现在虚拟机的流量不再受到速率限制时,我感到很失望。我希望来自其他物理机器的以太网帧能够携带来自网桥端口 1(即物理网络适配器)的 MAC 地址作为以太网源地址,因为这是它们进入网桥的端口。但(并不奇怪)事实并非如此。它们可能携带发送 PC 的物理网络适配器的 MAC 地址作为源地址。
所以我的问题是:
如何更改规则(集),使其与发往虚拟机 MAC 地址的流量匹配,但与源自本地的部分不匹配?主机生成的流量可能源自没有 MAC 地址的环回适配器,因此我不能使用类似ether saddr !<MAC of loopback>
.
我想过尝试ingress
而不是bridge
解决这个问题,或者使用按设备过滤。但可能的组合和陷阱的数量是无穷无尽的,因此有一个起点会让事情变得更容易。