[RFC PATCH 0/3] iproute2 bridge vlan support

The iproute2 bridge command supports the capability for VLAN filtering that allows each interface connected to a bridge to be configured to use one or more VLANs. For simple setups, this capability is enough to allow virtual machines or containers to be put onto separate VLANs without creating multiple bridges and VLANs on the host. The first patch adds a new function virNetDevBridgeSetupVlans() that will, given a virNetDevVlan structure, execute the required bridge vlan commands to configure the given interface accordingly. The second patch updates the virNetDevBridgeAddPort() function to allow a virNetDevVlan parameter to be passed, and to call the virNetDevBridgeSetupVlans() function. The third patch updates the lxc and tap code to pass the virNetDevLan parameter from the configuration and to update the XML validation to permit the VLAN-related tags for standard bridges. Usage example ============= Configure the host with systemd-networkd as follows: /etc/systemd/network/br0.netdev (br0.network not shown) [NetDev] Name=br0 Kind=bridge MACAddress=xx:xx:xx:xx:xx:xx [Bridge] VLANFiltering=on /etc/systemd/network/eno1.network [Match] Name=eno1 [Network] Bridge=br0 [Link] MTUBytes=9000 [BridgeVLAN] VLAN=40 [BridgeVLAN] VLAN=60 Then add <vlan> tags into the lxc or qemu config: lxc interface definition: <interface type='bridge'> <mac address='xx:xx:xx:xx:xx:xx'/> <source bridge='br0'/> <vlan> <tag id='40'/> </vlan> </interface> qemu interface definition: <interface type='network'> <mac address='xx:xx:xx:xx:xx:xx'/> <source network='br0'/> <vlan> <tag id='60'/> </vlan> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </interface> Then, after starting them, you will see the following $ sudo bridge vlan port vlan-id eno1 1 PVID Egress Untagged 40 60 br0 1 PVID Egress Untagged vnet0 60 PVID Egress Untagged vnet1 40 PVID Egress Untagged This is an RFC because I am not very familiar with the code, but all feedback is welcome! Regards, Leigh. Leigh Brown (3): util: bridge: add virNetDevBridgeSetupVlans() util: bridge: virNetDevBridgeAddPort vlan support util: bridge: enable bridge vlan support meson.build | 1 + src/conf/domain_validate.c | 3 +- src/lxc/lxc_process.c | 3 +- src/util/virnetdevbridge.c | 65 +++++++++++++++++++++++++++++++++++--- src/util/virnetdevbridge.h | 4 ++- src/util/virnetdevtap.c | 2 +- 6 files changed, 70 insertions(+), 8 deletions(-) -- 2.39.5

In preparation for adding vlan support using iproute2 bridge vlan functionality, add the virNetDevBridgeSetupVlans function that configures a bridge interface using the passed virNetDevVlan struct. Signed-off-by: Leigh Brown <leigh@solinno.co.uk> --- meson.build | 1 + src/util/virnetdevbridge.c | 54 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/meson.build b/meson.build index ca1b915737..39c01ebeef 100644 --- a/meson.build +++ b/meson.build @@ -857,6 +857,7 @@ optional_programs = [ 'ovs-vsctl', 'rmmod', 'tc', + 'bridge', ] + optional_test_programs missing_optional_programs = [] diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 5fd88f3195..0862342cee 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -24,6 +24,7 @@ #include "virfile.h" #include "virlog.h" #include "virstring.h" +#include "vircommand.h" #ifdef WITH_NET_IF_H # include <net/if.h> @@ -379,8 +380,61 @@ virNetDevBridgePortSetIsolated(const char *brname G_GNUC_UNUSED, _("Unable to set bridge port isolated on this platform")); return -1; } + #endif +static int +virNetDevBridgeSetupVlans(const char *ifname, const virNetDevVlan *virtVlan) +{ + g_autoptr(virCommand) cmd = NULL; + + if (!virtVlan || !virtVlan->nTags) + return 0; + + // The interface will have been automatically added to vlan 1, so remove it + cmd = virCommandNewArgList(BRIDGE, "vlan", "delete", + "dev", ifname, "vid", "1", NULL); + if (virCommandRun(cmd, NULL) < 0) + return -1; + + // If trunk mode, add the native VLAN then add any others + if (virtVlan->trunk) { + size_t i; + + virCommandFree(cmd); + cmd = virCommandNewArgList(BRIDGE, "vlan", "add", + "dev", ifname, "vid", NULL); + virCommandAddArgFormat(cmd, "%d", virtVlan->nativeTag); + virCommandAddArg(cmd, "pvid"); + if (virtVlan->nativeMode == VIR_NATIVE_VLAN_MODE_UNTAGGED) + virCommandAddArg(cmd, "untagged"); + if (virCommandRun(cmd, NULL) < 0) + return -1; + + for (i = 0; i < virtVlan->nTags; i++) { + if (virtVlan->tag[i] != virtVlan->nativeTag) { + virCommandFree(cmd); + cmd = virCommandNewArgList(BRIDGE, "vlan", "add", + "dev", ifname, "vid", NULL); + virCommandAddArgFormat(cmd, "%d", virtVlan->tag[i]); + if (virCommandRun(cmd, NULL) < 0) + return -1; + } + } + } else { + // In native mode, add the single VLAN as pvid untagged + virCommandFree(cmd); + cmd = virCommandNewArgList(BRIDGE, "vlan", "add", + "dev", ifname, "vid", NULL); + virCommandAddArgFormat(cmd, "%d", virtVlan->tag[0]); + virCommandAddArgList(cmd, "pvid", "untagged", NULL); + if (virCommandRun(cmd, NULL) < 0) + return -1; + } + + return 0; +} + /** * virNetDevBridgeCreate: -- 2.39.5

Add virVlan parameter to the Linux version of the virNetDevBridgeAddPort function. Update the function to pass the call virNetDevBridgeSetupVlans to run the appropriate iproute2 bridge vlan commands to set up the required vlan configuration. Update callers of this function to pass NULL for now. Signed-off-by: Leigh Brown <leigh@solinno.co.uk> --- src/lxc/lxc_process.c | 2 +- src/util/virnetdevbridge.c | 11 +++++++---- src/util/virnetdevbridge.h | 4 +++- src/util/virnetdevtap.c | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index cd8bcfc282..2a91896328 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -290,7 +290,7 @@ virLXCProcessSetupInterfaceTap(virDomainDef *vm, vport, virDomainNetGetActualVlan(net)) < 0) return NULL; } else { - if (virNetDevBridgeAddPort(brname, parentVeth) < 0) + if (virNetDevBridgeAddPort(brname, parentVeth, NULL) < 0) return NULL; if (virDomainNetGetActualPortOptionsIsolated(net) == VIR_TRISTATE_BOOL_YES && diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 0862342cee..e0fa2ad15b 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -647,7 +647,8 @@ int virNetDevBridgeDelete(const char *brname G_GNUC_UNUSED) */ #if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDIF) int virNetDevBridgeAddPort(const char *brname, - const char *ifname) + const char *ifname, + const virNetDevVlan *virtVlan) { struct ifreq ifr; VIR_AUTOCLOSE fd = -1; @@ -667,11 +668,12 @@ int virNetDevBridgeAddPort(const char *brname, return -1; } - return 0; + return virNetDevBridgeSetupVlans(ifname, virtVlan); } #elif defined(WITH_BSD_BRIDGE_MGMT) int virNetDevBridgeAddPort(const char *brname, - const char *ifname) + const char *ifname, + const virNetDevVlan *virtVlan) { struct ifbreq req = { 0 }; @@ -692,7 +694,8 @@ int virNetDevBridgeAddPort(const char *brname, } #else int virNetDevBridgeAddPort(const char *brname, - const char *ifname) + const char *ifname, + const virNetDevVlan *virtVlan) { virReportSystemError(ENOSYS, _("Unable to add bridge %1$s port %2$s"), brname, ifname); diff --git a/src/util/virnetdevbridge.h b/src/util/virnetdevbridge.h index db4099bf0b..5f51656abe 100644 --- a/src/util/virnetdevbridge.h +++ b/src/util/virnetdevbridge.h @@ -20,6 +20,7 @@ #include "internal.h" #include "virmacaddr.h" +#include "virnetdevvlan.h" int virNetDevBridgeCreate(const char *brname, const virMacAddr *mac) @@ -28,7 +29,8 @@ int virNetDevBridgeDelete(const char *brname) ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT; int virNetDevBridgeAddPort(const char *brname, - const char *ifname) + const char *ifname, + const virNetDevVlan *virtVlan) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; int virNetDevBridgeRemovePort(const char *brname, diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 2701ba6dfc..a9573eb8e1 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -483,7 +483,7 @@ virNetDevTapAttachBridge(const char *tapname, return -1; } } else { - if (virNetDevBridgeAddPort(brname, tapname) < 0) + if (virNetDevBridgeAddPort(brname, tapname, NULL) < 0) return -1; if (isolatedPort == VIR_TRISTATE_BOOL_YES && -- 2.39.5

Allow VLAN configuration for bridge interfaces and pass the VLAN configuration when adding the tap interface to the bridge. Signed-off-by: Leigh Brown <leigh@solinno.co.uk> --- src/conf/domain_validate.c | 3 ++- src/lxc/lxc_process.c | 3 ++- src/util/virnetdevtap.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index 1034bb57f5..c7a79a0277 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2077,7 +2077,8 @@ virDomainActualNetDefValidate(const virDomainNetDef *net) (actualType == VIR_DOMAIN_NET_TYPE_DIRECT && virDomainNetGetActualDirectMode(net) == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) || (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE && - vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) { + vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) || + (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE && !vport))) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("interface %1$s - vlan tag not supported for this connection type"), macstr); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 2a91896328..7c8dc703ca 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -290,7 +290,8 @@ virLXCProcessSetupInterfaceTap(virDomainDef *vm, vport, virDomainNetGetActualVlan(net)) < 0) return NULL; } else { - if (virNetDevBridgeAddPort(brname, parentVeth, NULL) < 0) + if (virNetDevBridgeAddPort(brname, parentVeth, + virDomainNetGetActualVlan(net)) < 0) return NULL; if (virDomainNetGetActualPortOptionsIsolated(net) == VIR_TRISTATE_BOOL_YES && diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index a9573eb8e1..1dc77f0f5c 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -483,7 +483,7 @@ virNetDevTapAttachBridge(const char *tapname, return -1; } } else { - if (virNetDevBridgeAddPort(brname, tapname, NULL) < 0) + if (virNetDevBridgeAddPort(brname, tapname, virtVlan) < 0) return -1; if (isolatedPort == VIR_TRISTATE_BOOL_YES && -- 2.39.5
participants (1)
-
Leigh Brown