diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index c2982244f0..7c760cec40 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -289,7 +289,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 5fd88f3195..c79d0c79b7 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -313,6 +313,66 @@ virNetDevBridgePortSetIsolated(const char *brname, return virNetDevBridgePortSet(brname, ifname, "isolated", enable ? 1 : 0); } +static int +virNetDevBridgeSetupVlans(const char *ifname, const virNetDevVlan *virtVlan) +{ + int error = 0; + unsigned short flags; + + if (!virtVlan || !virtVlan->nTags) + return 0; + + // The interface will have been automatically added to vlan 1, so remove it + if (virNetlinkBridgeVlanFilterSet(ifname, RTM_DELLINK, 0, 1, &error) < 0) { + if (error != 0) { + virReportSystemError(-error, + _("error removing vlan filter from interface %1$s"), + ifname); + } + return -1; + } + + // If trunk mode, add the native VLAN then add the others, if any + if (virtVlan->trunk) { + size_t i; + + if (virtVlan->nativeTag) { + flags = BRIDGE_VLAN_INFO_PVID; + if (virtVlan->nativeMode == VIR_NATIVE_VLAN_MODE_UNTAGGED || + virtVlan->nativeMode == VIR_NATIVE_VLAN_MODE_DEFAULT) { + flags |= BRIDGE_VLAN_INFO_UNTAGGED; + } + + if (virNetlinkBridgeVlanFilterSet(ifname, RTM_SETLINK, flags, + virtVlan->nativeTag, &error) < 0) { + goto error; + } + } + + for (i = 0; i < virtVlan->nTags; i++) { + if (virtVlan->tag[i] != virtVlan->nativeTag) + if (virNetlinkBridgeVlanFilterSet(ifname, RTM_SETLINK, 0, + virtVlan->tag[i], &error) < 0) { + goto error; + } + } + } else { + // In native mode, add the single VLAN as pvid untagged + flags = BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED; + if (virNetlinkBridgeVlanFilterSet(ifname, RTM_SETLINK, flags, + virtVlan->tag[0], &error) < 0) { + goto error; + } + } + + return 0; + + error: + if (error != 0) + virReportSystemError(-error, _("error adding vlan filter to interface %1$s"), ifname); + return -1; +} + #else int @@ -593,7 +653,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; @@ -613,14 +674,20 @@ 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 }; + if (virtVlan) { + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; + } + if (virStrcpyStatic(req.ifbr_ifsname, ifname) < 0) { virReportSystemError(ERANGE, _("Network interface name '%1$s' is too long"), @@ -638,7 +705,8 @@ int virNetDevBridgeAddPort(const char *brname, } #else int virNetDevBridgeAddPort(const char *brname, - const char *ifname) + const char *ifname, + const virNetDevVlan *virtVlan G_GNUC_UNUSED) { 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 &&