Bearbeiten von „VLAN for virtual machines“

Wechseln zu: Navigation, Suche

Warnung: Du bist nicht angemeldet. Deine IP-Adresse wird öffentlich sichtbar, falls du Bearbeitungen durchführst. Sofern du dich anmeldest oder ein Benutzerkonto erstellst, werden deine Bearbeitungen zusammen mit anderen Beiträgen deinem Benutzernamen zugeordnet.

Die Bearbeitung kann rückgängig gemacht werden. Bitte prüfe den Vergleich unten, um sicherzustellen, dass du dies tun möchtest, und speichere dann unten deine Änderungen, um die Bearbeitung rückgängig zu machen.
Aktuelle Version Dein Text
Zeile 2: Zeile 2:
 
I wanted to update VLAN connections for virtual
 
I wanted to update VLAN connections for virtual
 
machines to newer technologies and put a question on
 
machines to newer technologies and put a question on
[https://unix.stackexchange.com/questions/392758/setup-vlan-on-linux-bridge-for-virtual-machines-with-systemd unix.stackexchange]. But I do not get any answer. It seems there is very
+
[https://unix.stackexchange.com/questions/392758/setup-vlan-on-linux-bridge-for-virtual-machines-with-systemd?noredirect=1#comment700641_392758 unix.stackexchange]. But I do not get any answer. It seems there is very
 
little knowledge for this out there. So I decided to work on it by myself
 
little knowledge for this out there. So I decided to work on it by myself
 
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 ==
I have Debian GNU/Linux 9.1 (stretch) on the host and on virtual machines for testing. Setup is described here: [[Setup KVM with console]]. I'm sitting on harley as host, my all day workstation.
+
I have Debian GNU/Linux 9.1 (stretch) on the host and on virtual machines for testing as described here: [[Setup KVM with console]]. I'm sitting on harley as host, my all day workstation.
 
Now I start the virtual machine, login and show its interface setting:
 
Now I start the virtual machine, login and show its interface setting:
 
  '''harley$''' virsh start --console deb9-test
 
  '''harley$''' virsh start --console deb9-test
Zeile 31: Zeile 32:
 
  Name=vlan10
 
  Name=vlan10
 
  [Network]
 
  [Network]
  DHCP=ipv4
+
  Address=192.168.10.57/24
IPv6AcceptRA=no
+
Gateway=192.168.10.1
LinkLocalAddressing=no
+
To test if we have connection direct after startup I append this to .bashrc:
To test if the virtual machine has connection I use:
+
  '''deb9-test$''' echo ping -c3 192.168.10.1 >> .bashrc
'''deb9-test$''' journalctl -b --no-hostname -u systemd-networkd.service
 
-- Logs begin at Fri 2017-09-15 17:09:51 CEST, end at Sat 2017-09-23 20:34:20 CEST. --
 
Sep 23 20:34:05 systemd-networkd[204]: Enumeration completed
 
Sep 23 20:34:05 systemd[1]: Started Network Service.
 
Sep 23 20:34:05 systemd-networkd[204]: vlan10: netdev ready
 
Sep 23 20:34:05 systemd-networkd[204]: ens2: IPv6 enabled for interface: Success
 
Sep 23 20:34:05 systemd-networkd[204]: ens2: Gained carrier
 
Sep 23 20:34:05 systemd-networkd[204]: vlan10: Gained carrier
 
Sep 23 20:34:06 systemd-networkd[204]: ens2: Gained IPv6LL
 
Sep 23 20:34:06 systemd-networkd[204]: vlan10: Gained IPv6LL
 
Sep 23 20:34:09 systemd-networkd[204]: vlan10: DHCPv4 address 192.168.10.89/24 via 192.168.10.1
 
Sep 23 20:34:09 systemd-networkd[204]: vlan10: Configured
 
Sep 23 20:34:19 systemd-networkd[204]: ens2: Configured
 
'''deb9-test$'''
 
4 sec after Started Network Service it gets an IP-Address and 14 sec later interface ens2 was Configured. If ens2 is Configured and the guest hasn't got an IP-Address the connection failed. It looks like this:
 
  '''deb9-test$''' journalctl -b --no-hostname -u systemd-networkd.service
 
-- Logs begin at Fri 2017-09-15 17:09:51 CEST, end at Sat 2017-09-23 20:45:13 CEST. --
 
Sep 23 20:44:59 systemd-networkd[197]: Enumeration completed
 
Sep 23 20:44:59 systemd[1]: Started Network Service.
 
Sep 23 20:44:59 systemd-networkd[197]: vlan10: netdev ready
 
Sep 23 20:44:59 systemd-networkd[197]: ens2: IPv6 enabled for interface: Success
 
Sep 23 20:44:59 systemd-networkd[197]: ens2: Gained carrier
 
Sep 23 20:44:59 systemd-networkd[197]: vlan10: Gained carrier
 
Sep 23 20:45:00 systemd-networkd[197]: ens2: Gained IPv6LL
 
Sep 23 20:45:00 systemd-networkd[197]: vlan10: Gained IPv6LL
 
Sep 23 20:45:13 systemd-networkd[197]: ens2: Configured
 
'''deb9-test$'''
 
 
 
 
Because I have to start the test virtual machine many times I setup autologin. It's no problem. There is nothing on the guest.
 
Because I have to start the test virtual machine many times I setup autologin. It's no problem. There is nothing on the guest.
 
  '''deb9-test$''' grep ^ExecStart= /lib/systemd/system/serial-getty@.service
 
  '''deb9-test$''' grep ^ExecStart= /lib/systemd/system/serial-getty@.service
Zeile 68: Zeile 41:
 
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:
 
'''harley$''' find /sys/class/net/br0/bridge/ -type f -readable -printf '%f = ' -exec cat {} \; | sort
 
  
 
== oldstyle linux bridge as hub ==
 
== oldstyle linux bridge as hub ==
Zeile 105: Zeile 76:
 
  0
 
  0
 
Yes, there is no VLAN filtering, means VLAN on the bridge is disabled but the guest sees the VLAN-tagged packets.
 
Yes, there is no VLAN filtering, means VLAN on the bridge is disabled but the guest sees the VLAN-tagged packets.
 +
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
  
 
=== References ===
 
=== References ===
Zeile 139: Zeile 112:
 
  [Match]
 
  [Match]
 
  Name=br0
 
  Name=br0
'''harley$''' sudo ip link set dev br0 down && sudo ip link del dev br0
 
 
  '''harley$''' sudo systemctl restart systemd-networkd
 
  '''harley$''' sudo systemctl restart systemd-networkd
 
  '''harley$'''
 
  '''harley$'''
  
AgeingTimeSec=0 is not acepted but should:
+
But AgeingTimeSec=0 is not acepted:
 
  '''harley$''' cat /sys/class/net/br0/bridge/ageing_time  
 
  '''harley$''' cat /sys/class/net/br0/bridge/ageing_time  
 
  30000  (means 300 sec)
 
  30000  (means 300 sec)
'''harley$'''
 
But I've found a workaround. Useing a number between '''.'''01 and '''.'''000001 (there are dots) will set ageing_time to 0.
 
So set AgeingTimeSec='''.'''000001 in /etc/systemd/network/08-br0.netdev. I suppose it's a bug. Then we
 
will get:
 
'''harley$''' cat /sys/class/net/br0/bridge/ageing_time
 
0
 
 
  '''harley$''' cat /sys/class/net/br0/bridge/stp_state  
 
  '''harley$''' cat /sys/class/net/br0/bridge/stp_state  
 
  0
 
  0
Zeile 157: Zeile 123:
 
  0
 
  0
 
  '''harley$'''
 
  '''harley$'''
The guest gets now an IP-Address on boot and is connected to VLAN 10.
 
 
=== Discussion ===
 
This works because of [[#References|three conditions]].
 
# ageing time is 0: ageing time specifies the number of seconds a MAC Address will be kept in the forwarding database after having a packet received from this MAC Address. Setting it to 0 means there is never a MAC Address stored in the FDB.
 
# unicast flood on interfaces is on: this controls whether the bridge should flood traffic for which an FDB entry is missing and the destination is unknown through this port. Defaults to on.
 
# spanning tree protocol (stp) is disabled: we don't have a forward_delay at startup for the learning phase of spanning tree.
 
I have a running and connected virtual machine:
 
'''harley$''' sudo bridge vlan show
 
port    vlan ids
 
enp1s0  1 PVID Egress Untagged
 
br0      1 PVID Egress Untagged
 
vnet0    1 PVID Egress Untagged
 
'''harley$''' cat /sys/class/net/br0/bridge/ageing_time
 
0
 
'''harley$''' cat /sys/class/net/br0/bridge/forward_delay
 
1500
 
'''harley$''' cat /sys/class/net/br0/bridge/stp_state
 
0
 
Indeed we have forward_delay 1500 (means 15 sec) but it doesn't matter. stp_state is 0 (disabled), no spanning tree. Flood (means unicast flood) is on as I can see:
 
'''harley$''' sudo bridge -d link show
 
''3: enp1s0'' state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 4
 
    hairpin off guard off root_block off fastleave off learning on flood on mcast_flood on
 
''95: vnet0'' state UNKNOWN : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
 
    hairpin off guard off root_block off fastleave off learning on flood on mcast_flood on
 
'''harley$'''
 
 
 
Let's have a look at flooding on the interfaces. I disable it on the physical interface enp1s0 of the bridge and reboot the guest:
 
'''harley$''' sudo bridge link set dev enp1s0 flood off
 
'''harley$'''
 
The guest gets an IP-Address from the DHCP-Server but then can't ping its gateway. DHCP-REQUEST is broadcast and goes thru enp1s0. DHCP-ANSWER comes back thru it to any other (here only vnet0) interface which has flood on. Ping is unicast and isn't forwareded on enp1s0. If I set  enp1s0 flood on and vnet0 flood off and <code>'''deb9-test$ '''sudo systemctl restart systemd-networkd</code>, I get no IP-Address from DHCP-Server and can't ping the interface. Incoming DHCP-ANSWER isn't broadcast and vnet0 doesn't forward it to the guest.
 
 
Btw. this method has bad performance as we can see with monitor. We insert MAC-Addresses into FDB for just deleting it immediately, all for nothing.
 
'''harley$''' sudo bridge monitor fdb
 
52:54:00:01:76:20 dev enp1s0 master br0
 
52:54:00:b0:ca:63 dev vnet0 master br0
 
f4:f2:6d:2c:87:f7 dev enp1s0 master br0
 
00:80:3f:2a:31:1a dev enp1s0 master br0
 
Deleted 52:54:00:01:76:20 dev enp1s0 master br0 stale
 
Deleted 52:54:00:b0:ca:63 dev vnet0 master br0 stale
 
Deleted 00:80:3f:2a:31:1a dev enp1s0 master br0 stale
 
Deleted f4:f2:6d:2c:87:f7 dev enp1s0 master br0 stale
 
...
 
  
 
=== References ===
 
=== References ===
Zeile 207: Zeile 129:
  
 
== 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"?>
 
&lt;!-- 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>
 
--&gt;
 
<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 &#91;[ -n $DEV && -n $VLAN ]&#93;; 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 &#91;[ -f $BRDIR/vlan_filtering && -f $BRDIR/default_pvid ]&#93;; 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]]

Bitte beachte, dass alle Beiträge zu Ingos Wiki von anderen Mitwirkenden bearbeitet, geändert oder gelöscht werden können. Reiche hier keine Texte ein, falls du nicht willst, dass diese ohne Einschränkung geändert werden können.

Du bestätigst hiermit auch, dass du diese Texte selbst geschrieben hast oder diese von einer gemeinfreien Quelle kopiert hast (weitere Einzelheiten unter My wiki:Urheberrechte). ÜBERTRAGE OHNE GENEHMIGUNG KEINE URHEBERRECHTLICH GESCHÜTZTEN INHALTE!

Abbrechen | Bearbeitungshilfe (wird in einem neuen Fenster geöffnet)