Aktuelle Version |
Dein Text |
Zeile 6: |
Zeile 6: |
| and document it here. | | and document it here. |
| | | |
− | In gerneral I will look at three methods: | + | In gerneral I will look at four methods: |
| # [[#oldstyle linux bridge as hub|oldstyle linux bridge as hub]] | | # [[#oldstyle linux bridge as hub|oldstyle linux bridge as hub]] |
| # [[#linux bridge as hub|linux bridge as hub]] | | # [[#linux bridge as hub|linux bridge as hub]] |
| # [[#linux bridge with libvirt hook scripts|linux bridge with libvirt hook scripts]] | | # [[#linux bridge with libvirt hook scripts|linux bridge with libvirt hook scripts]] |
| + | # [[#Open vSwitch|Open vSwitch]] |
| | | |
| == Preparation == | | == Preparation == |
Zeile 68: |
Zeile 69: |
| modify to | | modify to |
| ExecStart=-/sbin/agetty --autologin ''yourloginname'' --keep-baud 115200,38400,9600 %I $TERM | | ExecStart=-/sbin/agetty --autologin ''yourloginname'' --keep-baud 115200,38400,9600 %I $TERM |
− | <span id="bridge-settings">To list all settings of the bridge</span> you can use:
| + | To list all settings of the bridge you can use: |
| '''harley$''' find /sys/class/net/br0/bridge/ -type f -readable -printf '%f = ' -exec cat {} \; | sort | | '''harley$''' find /sys/class/net/br0/bridge/ -type f -readable -printf '%f = ' -exec cat {} \; | sort |
| | | |
Zeile 207: |
Zeile 208: |
| | | |
| == linux bridge with libvirt hook scripts == | | == linux bridge with libvirt hook scripts == |
− | We setup a bridge with VLAN enabled:
| |
− | '''harley$''' cat /etc/systemd/network/08-br0.netdev
| |
− | [NetDev]
| |
− | Name=br0
| |
− | Kind=bridge
| |
− | [Bridge]
| |
− | DefaultPVID=none
| |
− | 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
| |
− | With this I get:
| |
− | '''harley$''' sudo bridge vlan show
| |
− | port vlan ids
| |
− | enp1s0 1 PVID Egress Untagged
| |
− | 10
| |
− | 20
| |
− | 30
| |
− | br0 1 PVID Egress Untagged
| |
− | '''harley$'''
| |
− | But what is this? We have default VLAN <code>1 PVID Egress Untagged</code>. I don't want this. Seems setting <code>DefaultPVID=none</code> in 08-br0.netdev doesn't work. I've made a [[#Workaround for setting DefaultPVID=none|Workaround for setting DefaultPVID=none]]. Looking at this behavior I found that we can set <code>default_pvid</code> in the kernel only if <code>vlan_filtering = 0</code>. By hand I have to do:
| |
− | '''harley$''' sudo bash -c 'echo 0 >/sys/class/net/br0/bridge/vlan_filtering'
| |
− | '''harley$''' sudo bash -c 'echo 0 >/sys/class/net/br0/bridge/default_pvid'
| |
− | '''harley$''' sudo bash -c 'echo 1 >/sys/class/net/br0/bridge/vlan_filtering'
| |
− | '''harley$'''
| |
− | If I start a guest I will get now:
| |
− | '''harley$''' virsh start deb9-test
| |
− | '''harley$''' sudo bridge vlan show
| |
− | port vlan ids
| |
− | enp1s0 10
| |
− | 20
| |
− | 30
| |
− | br0 None
| |
− | vnet0 None
| |
− | '''harley$'''
| |
− | The virtual network interface vnet0 for deb9-test has no VLAN ID. Libvirt does not know something about this so we have to tell it. Libvirt provides [https://www.libvirt.org/hooks.html hook scripts] that we can use for this. We have to:
| |
− | # [[#define VLAN-ID the virtual machine belongs to]]
| |
− | # [[#get information on startup from the runtime XML-config of the domain]]
| |
− | # [[#set VLAN-ID to the dynamic virtual network interface vnet*]]
| |
− | <span id="debug.sh">For debugging the hook-scripts</span> I've made a small script:
| |
− | '''harley$''' cat /etc/libvirt/hooks/debug.sh
| |
− | #!/bin/bash -e
| |
− | # https://www.libvirt.org/hooks.html
| |
− | # If you make a new hook script then 'sudo systemctl restart libvirtd'.
| |
− | # For debug set symlink to hook-script daemon, qemu, lxc, libxl and/or network,
| |
− | # e.g. 'sudo ln -s debug.sh qemu' and restart libvirtd.
| |
− |
| |
− | logfile='/var/log/libvirt/hooks.log'
| |
− |
| |
− | echo "$0" >>$logfile
| |
− | date -Iseconds >>$logfile
| |
− | echo "\$1=$1, \$2=$2, \$3=$3, \$4=$4" >>$logfile
| |
− | cat - >>$logfile
| |
− | echo -e "\n---------------------------------------------" >>$logfile
| |
− | '''harley$'''
| |
− |
| |
− | === define VLAN-ID the virtual machine belongs to ===
| |
− | For this we have an extra [https://libvirt.org/formatdomain.html#elementsMetadata element <metadata> in Domain XML format] for custom metadata. We can simply add the information to the static configuration with <code>'''harley$''' virsh edit deb9-test</code> like this (look only at the <metadata> element):
| |
− | '''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>
| |
− |
| |
− | === get information on startup from the runtime XML-config of the domain ===
| |
− | It seems a little bit difficult to get needed information out of the big XML-config but it's no problem with XSLT. I've made a XSL-stylesheet for this and use xmlstarlet. Start a virtual machine and then its runtime configuration is available with <code>'''harley$''' virsh dumpxml deb9-test | xmlstarlet tr qemu.xsl</code>. With this I can test my stylesheet. Here is it:
| |
− | '''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$'''
| |
− |
| |
− | '''harley$''' virsh dumpxml deb9-test | xmlstarlet tr /etc/libvirt/hooks/qemu.xsl
| |
− | <meta><vlan>10</vlan><dev>vnet0</dev></meta>'''harley$'''
| |
− |
| |
− | === set VLAN-ID to the dynamic virtual network interface vnet* ===
| |
− | Putting it all together here is the executable hook-script:
| |
− | '''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$''' sudo chmod 744 /etc/libvirt/hooks/qemu
| |
− | '''harley$'''
| |
− |
| |
| === References === | | === References === |
| * https://www.libvirt.org/hooks.html | | * https://www.libvirt.org/hooks.html |
| * https://serverfault.com/questions/696011/libvirt-hook-qemu-suse12 | | * https://serverfault.com/questions/696011/libvirt-hook-qemu-suse12 |
| | | |
− | == Workaround for setting DefaultPVID=none == | + | == Open vSwitch == |
− | <span style="color:red">We do not need it anymore. This bug is fixed in systemd 234.</span>
| + | === References === |
− | | + | * https://libvirt.org/formatnetwork.html |
− | Setting [https://www.freedesktop.org/software/systemd/man/systemd.netdev.html#DefaultPVID= DefaultPVID] in a<code>systemd-networkd</code> configuration file to "none" does not work. Until this bug is fixed I've made a workaround. The kernel accepts setting <code>default_pvid</code> to 0 (means "none") only if <code>vlan_filtering=0</code>, so we have to do:
| |
− | '''harley$''' sudo bash -c 'echo 0 >/sys/class/net/br0/bridge/vlan_filtering'
| |
− | '''harley$''' sudo bash -c 'echo 0 >/sys/class/net/br0/bridge/default_pvid'
| |
− | '''harley$''' sudo bash -c 'echo 1 >/sys/class/net/br0/bridge/vlan_filtering'
| |
− | '''harley$'''
| |
− | Check with listing of [[#bridge-settings|bridge-settings]].
| |
− | Theese commands must run with <code>systemd-networkd</code> so we need a service for this. First I make a script and make it executable for root:
| |
− | '''harley$''' cat /etc/systemd/network/DefaultPVID.sh
| |
− | #!/bin/bash
| |
− | #echo "entering DefaultPVID.sh" >>/tmp/debug.log
| |
− |
| |
− | BRDIR="/sys/class/net/br0/bridge/"
| |
− |
| |
− | if [[ -f $BRDIR/vlan_filtering && -f $BRDIR/default_pvid ]]; then
| |
− | #echo "setting DefaultPVID" >>/tmp/debug.log
| |
− | VLAN_FILTERING="$(cat "$BRDIR"/vlan_filtering)"
| |
− | echo 0 >"$BRDIR"/vlan_filtering
| |
− | echo 0 >"$BRDIR"/default_pvid
| |
− | echo "$VLAN_FILTERING" >"$BRDIR"/vlan_filtering
| |
− | fi
| |
− | exit 0
| |
− | '''harley$''' sudo chmod 744 /etc/systemd/network/DefaultPVID.sh
| |
− | '''harley$'''
| |
− | Test with <code>'''harley$''' sudo /etc/systemd/network/DefaultPVID.sh</code>. Next I create a service to execute this script:
| |
− | '''harley$''' cat /etc/systemd/system/DefaultPVID.service
| |
− | [Unit]
| |
− | Description=set DefaultPVID on a bridge as workaround
| |
− | Wants=network.target
| |
− | After=network.target
| |
− |
| |
− | [Service]
| |
− | Type=oneshot
| |
− | ExecStart=/etc/systemd/network/DefaultPVID.sh
| |
− |
| |
− | [Install]
| |
− | WantedBy=multi-user.target
| |
− | '''harley$'''
| |
− | Test with <code>'''harley$''' sudo systemctl start DefaultPVID.service && systemctl status DefaultPVID.service</code>. After this I create a [https://www.freedesktop.org/software/systemd/man/systemd.unit.html#id-1.11.3 drop-in file for overriding vendor settings] so this service will be executed together with <code>systemd-networkd</code>:
| |
− | '''harley$''' cat /etc/systemd/system/systemd-networkd.service.d/DefaultPVID.conf
| |
− | [Unit]
| |
− | # This is only a workaround. DefaultPVID cannot be set in
| |
− | # /etc/systemd/network/br0.netdev. It seems buggy.
| |
− | Wants=DefaultPVID.service
| |
− | Before=DefaultPVID.service
| |
− | '''harley$'''
| |
− | Test with <code>'''harley$''' sudo systemctl restart systemd-networkd</code>.
| |
| | | |
| [[Category:Virtualization]] | | [[Category:Virtualization]] |