AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 1051294
Accepted
Ingo
Ingo
Asked: 2021-01-27 09:42:45 +0800 CST2021-01-27 09:42:45 +0800 CST 2021-01-27 09:42:45 +0800 CST

使用 libvirt 为 Linux 桥接虚拟机提供 VLAN 支持

  • 772

我正在使用systemd-networkd在所有节点上使用Debian Bullseye为KVM(基于内核的虚拟机)配置由libvirt管理的网络接口。我想在使用Linux Bridge的虚拟机上支持透明 VLAN 。对于 Linux Bridge,这不受libvirt支持。

例如,我有一个虚拟机,其三个接口连接到网桥:

host ~$ virsh attach-interface guest-vm bridge br0 --config
host ~$ virsh attach-interface guest-vm bridge br0 --config
host ~$ virsh attach-interface guest-vm bridge br0 --config

现在,当运行来宾时,我将在桥上看到:

host ~$ sudo bridge link
3: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
30: vnet13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
31: vnet14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
32: vnet15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100

所有接口都成功连接到网桥。enp1s0是主机上的上行链路接口。现在查看网桥上的 VLAN id 时,我看到:

~$ sudo bridge vlan
port              vlan-id
enp1s0            10
                  26
                  30
                  50

仅显示主机接口及其 VLAN id。

有没有办法将 VLAN id 附加到vnet*来宾的其他接口,以便它可以使用它们?

debian vlan kvm-virtualization bridge systemd-networkd
  • 2 2 个回答
  • 4186 Views

2 个回答

  • Voted
  1. Best Answer
    Ingo
    2021-01-27T09:42:45+08:002021-01-27T09:42:45+08:00

    我已经解决了这个问题并找到了解决方案。手动添加 VLAN id 到网桥的从接口是没有问题的,例如:

    host ~$ sudo bridge vlan add vid 26 dev vnet13 pvid 26 untagged
    host ~$ sudo bridge vlan add vid 30 dev vnet13
    host ~$ sudo bridge vlan add vid 50 dev vnet14
    
    host ~$ $ sudo bridge vlan
    port              vlan-id
    enp1s0            10
                      26
                      30
                      50
    vnet13            26 PVID Egress Untagged
                      30
    vnet14            50
    

    问题是在虚拟机启动时自动执行此操作。幸运的是libvirt支持libvirt 挂钩脚本。我将使用qemu的钩子脚本并分三步完成。

    第 1 步:定义哪个 VLAN-ID 连接到哪个接口

    为此,我们为自定义元数据提供了域 XML 格式的额外元素 <metadata>。我们可以简单地将信息添加到域(虚拟机)的静态配置中:

    host ~$ virsh edit guest-vm
    --- snip ---
    <metadata>
      <my:home xmlns:my="http://hoeft-online.de/libvirt">
        <my:iface pvid="26">
          <my:vlan untagged="yes">26</my:vlan>
          <my:vlan>50</my:vlan>
          <my:vlan untagged="no">30</my:vlan>
        </my:iface>
        <my:iface>
          <my:vlan untagged="yes">50</my:vlan>
          <my:vlan>10</my:vlan>
        </my:iface>
      </my:home>
    </metadata>
    --- snap ---
    

    正如文档所给出的,我必须使用我自己的自定义命名空间<my:home xmlns:my="http://hoeft-online.de/libvirt">。一旦创建,在命名空间中工作就更容易了:

    host ~$ virsh metadata guest-vm http://hoeft-online.de/libvirt [--edit --key my]
    <home>
      <iface pvid="26">
        <vlan untagged="yes">26</vlan>
        <vlan>50</vlan>
        <vlan untagged="no">30</vlan>
      </iface>
      <iface>
        <vlan untagged="yes">50</vlan>
        <vlan>10</vlan>
      </iface>
    </home>
    

    步骤 2:从域的运行时 XML-config 获取启动信息

    挂钩脚本获取有关其标准输入的信息。这是正在运行的 VM 的 XML 配置。我们也可以virsh dumpxml guest-vm在虚拟机运行时获取它。我将 XSLT 与xmlstarlet一起使用,以通过 xsl 样式表获取所需的信息。我可以测试:

    host ~$ virsh dumpxml guest-vm | xmlstarlet transform /etc/libvirt/hooks/qemu.xsl | xmlstarlet format
    

    这是样式表:

    host ~$ cat /etc/libvirt/hooks/qemu.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- This stylesheet processes the live XML configuration output from a virtual
         machine managed by libvirt. It transforms the custom metadata information
         together with attached interfaces and returns a normalized XML with VLAN
         ids attached to the interface. For further information look at the
         README file.
         Author: 2021-01-26 - Ingo Höft ([email protected])
         Licence: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
    -->
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:my="http://hoeft-online.de/libvirt" 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='*'>
        <xsl:for-each select='interface[@type="bridge"]/target'>
        <iface>
          <xsl:variable name="_index" select="position()" />
    
          <xsl:attribute name="pvid">
            <xsl:choose>
              <xsl:when test="/*/metadata/my:home/my:iface[$_index]/@pvid != ''">
                <xsl:value-of select="/*/metadata/my:home/my:iface[$_index]/@pvid"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:text>0</xsl:text>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
    
          <xsl:value-of select="@dev"/>
    
          <xsl:for-each select="/*/metadata/my:home/my:iface[$_index]/my:vlan">
            <vlan>
              <xsl:attribute name="untagged">
                <xsl:choose>
                  <xsl:when test="@untagged='yes'">
                    <xsl:text>yes</xsl:text>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:text>no</xsl:text>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:attribute>
    
              <xsl:value-of select="."/>
            </vlan>
          </xsl:for-each>
    
        </iface>
        </xsl:for-each>
      </xsl:template>
    
    <!-- vim: set sts=2 sw=2 et autoindent nowrap: -->
    </xsl:stylesheet>
    

    第 3 步:将 VLAN-ID 设置为动态虚拟网络接口 vnet *

    使用样式表中的信息,我们现在可以使用挂钩脚本设置网络接口。使其可执行。

    harley$ cat /etc/libvirt/hooks/qemu
    #!/usr/bin/bash
    # /etc/libvirt/hooks/qemu
    # Docs: https://www.libvirt.org/hooks.html
    
    # Author: 2021-01-26 - Ingo Höft ([email protected])
    # Licence: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
    
    # If you save a modified hook script then do 'sudo systemctl restart libvirtd'.
    
    # This script adds VLAN support to interfaces of libvirt guests on start up.
    # For more details look at the README file.
    # Most work is done with the powerful XML transformation of the XML
    # configuration of the guest on stdin with qemu.xsl to get a normalized
    # meta information into $META, for example like this
    # (we need it to understand the script):
    #
    # <?xml version="1.0"?>
    # <meta>
    #   <iface pvid="26">vnet1
    #     <vlan untagged="yes">26</vlan>
    #     <vlan untagged="no">50</vlan>
    #     <vlan untagged="no">30</vlan>
    #   </iface>
    #   <iface pvid="30">vnet2
    #     <vlan untagged="yes">30</vlan>
    #     <vlan untagged="no">50</vlan>
    #   </iface>
    #   <iface pvid="0">vnet3</iface>
    # </meta>
    
    # for DEBUG uncomment/comment next three lines
    #exec 0< start-vdeb11-base02.xml  # for DEBUG: read testfile to stdin
    #BRIDGE="/usr/bin/echo"
    BRIDGE="/usr/sbin/bridge"
    # and call it with ./qemu "dummy-vm" "start" "begin" "-"
    
    XSLFILE="/etc/libvirt/hooks/qemu.xsl"
    XMLPROG="/usr/bin/xmlstarlet"
    
    #GUEST=$1       # name of guest being started
    OPERATION=$2
    SUB_OPERATION=$3
    EXTRA_PARM=$4
    
    
    #echo 'DEBUG: entering qemu.hook' >&2
    case "$OPERATION" in
        prepare)
          ;;
        start)
            if [[ "$SUB_OPERATION" != "begin" ]] || [[ "$EXTRA_PARM" != "-" ]]; then
                echo "Error: Unhandled parameter \$3='$SUB_OPERATION' or \$4='$EXTRA_PARM' to $0 \$1 \$2 \$3 \$4" >&2
                exit 1
            fi
            if [[ ! -x "$XMLPROG" ]]; then
                echo "Error: $XMLPROG is not executable" >&2
                exit 1
            fi
    
            #cat - >/var/log/libvirt/start-"$1".xml; exit 1   # get live xml for DEBUG
            META=$("$XMLPROG" tr "$XSLFILE" -)
            #echo "DEBUG: using hook start with $META" >&2
    
            # loop through interfaces
            IFACE_COUNT=0
            while true; do
                ((++IFACE_COUNT))
                IFACE=$(echo "$META" | "$XMLPROG" sel -t -c "/meta/iface[$IFACE_COUNT]/text()")
                if [[ -z "$IFACE" ]]; then
                    # finished, no more interfaces available
                    exit 0
                fi
    
                "$BRIDGE" link set dev "$IFACE" flood off
    
                # loop through vlans on one interface
                VLAN_COUNT=0
                while true; do
                    ((++VLAN_COUNT))
                    VLAN=$(echo "$META" | "$XMLPROG" sel -t -v "/meta/iface[$IFACE_COUNT]/vlan[$VLAN_COUNT]/text()")
                    if [[ -z "$VLAN" ]]; then
                        # finished, no more vlans available, process next interface
                        break
                    else
                        UNTAGGED=$(echo "$META" | "$XMLPROG" sel -t -v "/meta/iface[$IFACE_COUNT]/vlan[$VLAN_COUNT]/@untagged")
                        if [[ "$UNTAGGED" == "yes" ]]; then
                            "$BRIDGE" vlan add vid "$VLAN" dev "$IFACE" pvid "$VLAN" untagged
                        else
                            "$BRIDGE" vlan add vid "$VLAN" dev "$IFACE"
                        fi
                    fi
                done
            done
            ;;
        started)
            ;;
        stopped)
            ;;
        release)
            ;;
        migrate)
            ;;
        restore)
            ;;
        reconnect)
            ;;
        attach)
            ;;
        *)
            echo "Error: qemu hook called with unexpected options $*" >&2
            exit 1
            ;;
    esac
    
    # vim: set sts=4 sw=4 et autoindent nowrap:
    
    • 1
  2. modzilla
    2022-02-07T05:50:49+08:002022-02-07T05:50:49+08:00

    感谢@Ingo 的想法,虽然他的(可能)解决方案效果很好,但我真的不想使用 xmlstarlet,因为它不在 Centos Stream 9 的存储库中。

    无论如何,我使用了 Ingos 的想法并在 python 中实现了它。唯一需要的是python。

    https://github.com/modzilla99/libvirt-vlans

    • 1

相关问题

  • 关闭 FTP

  • 如何在同一台电脑上从 putty 连接 debian vmware

  • debian- 文件到包的映射

  • Debian Ubuntu 网络管理器错误 [关闭]

  • 为本地网络中的名称解析添加自定义 dns 条目

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve