![使用 systemd 在 Linux 桥上为虚拟机设置 VLAN](https://linux22.com/image/118097/%E4%BD%BF%E7%94%A8%20systemd%20%E5%9C%A8%20Linux%20%E6%A1%A5%E4%B8%8A%E4%B8%BA%E8%99%9A%E6%8B%9F%E6%9C%BA%E8%AE%BE%E7%BD%AE%20VLAN.png)
我想切换到系统这样我就必须为 KVM 中的虚拟机设置 linux 桥接器才能使用 VLAN。
拥有 Debian GNU/Linux 9.1 (stretch),使用其systemd-networkd和库虚拟机。不使用旧式网络ifupdown
(已卸载)。
我坐在哈雷上,这是我的全天工作站,用于在主机上测试和设置桥接器。
harley$ cat /etc/systemd/network/08-br0.netdev
[NetDev]
Name=br0
Kind=bridge
[Bridge]
VLANFiltering=true
STP=false
harley$ cat /etc/systemd/network/12-br0_add-enp1s0.network
[Match]
Name=enp1s0
[Network]
Bridge=br0
[BridgeVLAN]
VLAN=10
[BridgeVLAN]
VLAN=20
[BridgeVLAN]
VLAN=30
harley$ cat /etc/systemd/network/16-br0_up.network
[Match]
Name=br0
从测试中清理旧桥并从头开始设置新桥:
harley$ sudo ip link set dev br0 down && sudo ip link del dev br0
harley$ sudo systemctl restart systemd-networkd
harley$
现在一切都已就位:
harley$ cat /sys/class/net/br0/bridge/vlan_filtering
1
harley$ cat /sys/class/net/br0/bridge/stp_state
0
harley$ sudo bridge vlan show
port vlan ids
enp1s0 1 PVID Egress Untagged
10
20
30
br0 1 PVID Egress Untagged
harley$
现在我启动虚拟机,登录并显示其界面设置:
harley$ virsh start --console deb9-test
登录
deb9-test$ cat /etc/systemd/network/08-vlan10.netdev
[NetDev]
Name=vlan10
Kind=vlan
[VLAN]
Id=10
deb9-test$ cat /etc/systemd/network/12-vlan10_attach-to-if.network
[Match]
Name=ens2
[Network]
VLAN=vlan10
deb9-test$ cat /etc/systemd/network/16-vlan10_up.network
[Match]
Name=vlan10
[Network]
Address=192.168.10.57/24
Gateway=192.168.10.1
DNS=192.168.10.8
但现阶段 ping 网关没有给出任何结果:
deb9-test$ ping -c1 192.168.10.1
PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.
From 192.168.10.57 icmp_seq=1 Destination Host Unreachable
--- 192.168.10.1 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
桥现在显示:
harley$ sudo bridge vlan show
port vlan ids
enp1s0 1 PVID Egress Untagged
10
20
30
br0 1 PVID Egress Untagged
vnet0 1 PVID Egress Untagged
我必须修改它:
harley$ sudo bridge vlan del dev enp1s0 vid 1
harley$ sudo bridge vlan del dev br0 vid 1 self
harley$ sudo bridge vlan del dev vnet0 vid 1
harley$ sudo bridge vlan add vid 10 dev vnet0
虚拟机现在可以工作:
deb9-test$ ping -c1 192.168.10.1
PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.
64 bytes from 192.168.10.1: icmp_seq=1 ttl=64 time=0.843 ms
--- 192.168.10.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.843/0.843/0.843/0.000 ms
修改后这就是我想要的,简单干净:
harley$ sudo bridge vlan show
port vlan ids
enp1s0 10
20
30
br0 None
vnet0 10
最后是我的问题:
我怎样才能让 Debian 在虚拟机接口出现之前为我执行此操作,以便它可以通过 DHCP 获取其 IP 地址?
答案1
请注意:
此配置已弃用,不再受支持。我决定在服务器上继续过错在libvirt 支持 VLAN,用于 Linux 桥接到虚拟机,因为我认为根据政策它更适合该网站。如果您想要改进的脚本,请查看那里。
我已经研究过并找到了解决方案。简而言之。在那里寻找一个更详细的描述。
我们必须告知libvirt
将正确的 VLAN-ID 设置为在域(来宾)启动时添加到网桥的动态创建的虚拟网络接口(例如 vnet0)。为此我们可以使用libvirt 挂钩脚本。我分三步进行。
步骤1:定义虚拟机所属的VLAN-ID
为此我们有一个额外的域 XML 格式的元素 <metadata>用于自定义元数据。我们可以简单地将信息添加到静态配置中,如下harley$ virsh edit deb9-test
所示(仅查看 <metadata> 元素):
harley$ virsh dumpxml deb9-test | head -n9
<domain type='kvm' id='1'>
<name>deb9-test</name>
<uuid>70d56a28-795d-4010-9403-513a4bd6b66a</uuid>
<metadata>
<my:home xmlns:my="http://hoeft-online.de/my/">
<my:vlan>10</my:vlan>
</my:home>
</metadata>
<memory unit='KiB'>1048576</memory>
步骤 2:从域的运行时 XML 配置获取启动信息
这钩子脚本获取有关其标准输入的信息。这是正在运行的 VM 的 XML 配置。我们还可以harley$ virsh dumpxml deb9-test
在虚拟机运行时获取它。我使用 XSLT 通过xmlstarlet
xsl 样式表获取所需信息。我可以用 进行测试harley$ virsh dumpxml deb9-test | xmlstarlet tr qemu.xsl
。这是样式表:
harley$ cat /etc/libvirt/hooks/qemu.xsl
<?xml version="1.0" encoding="UTF-8"?>
<!-- This stylesheet extracts the VLAN-ID and the target device of the
bridge from the domain-xml given to the libvirt hook-script "qemu".
Example output: <meta><vlan>10</vlan><dev>vnet0</dev></meta>
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://hoeft-online.de/my/" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="no"
encoding="utf-8" media-type="text/xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()|@*"/>
<xsl:template match="/domain">
<meta>
<xsl:apply-templates/>
</meta>
</xsl:template>
<xsl:template match="metadata/my:home/my:vlan">
<vlan>
<xsl:value-of select="."/>
</vlan>
</xsl:template>
<xsl:template match='interface[@type="bridge"]/target'>
<dev>
<xsl:value-of select="@dev"/>
</dev>
</xsl:template>
</xsl:stylesheet>
harley$
步骤 3:将 VLAN-ID 设置为动态虚拟网络接口 vnet*
根据样式表中的信息,我们现在可以使用以下命令设置网络接口钩子脚本。使其可执行。
harley$ cat /etc/libvirt/hooks/qemu
#!/bin/bash
#/etc/libvirt/hooks/qemu
# Docs: https://www.libvirt.org/hooks.html
# If you make a new hook script then 'sudo systemctl restart libvirtd'.
# On startup of the domain (guest) This script does:
# Get Metadata VLAN-ID of the guest and target device of the bridge from
# the domain-xml available on standard input. It is the runtime
# version from 'virsh dumpxml domainname'. For extracting the
# information we use a XSL-stylesheet. Example input into $META:
# <meta><vlan>10</vlan><dev>vnet0</dev></meta>
# Select $DEV from $META
# Select $VLAN from $META
# Set $VLAN to $DEV on the bridge
case "$2" in
prepare)
;;
start)
META=$(/usr/bin/xmlstarlet tr /etc/libvirt/hooks/qemu.xsl -)
DEV=$(echo "$META" | /usr/bin/xmlstarlet sel -t -v '/meta/dev')
VLAN=$(echo "$META" | /usr/bin/xmlstarlet sel -t -v '/meta/vlan')
if [[ -n $DEV && -n $VLAN ]]; then
/sbin/bridge vlan add vid "$VLAN" dev "$DEV"
fi
;;
started)
;;
stopped)
;;
release)
;;
migrate)
;;
restore)
;;
reconnect)
;;
attach)
;;
*)
echo "qemu hook called with unexpected options $*" >&2
exit 1
;;
esac
harley$