[libvirt] [PATCHv2 0/3] network: new network forward mode 'vlan'

Hi, everyone! This patch supports VLan by '8021q' kernel module other than by OVS. The way of '8021q' is simpler and more robust. Mode 'vlan' is like mode 'route' except these major differences: - mode 'vlan' inserts a vlan-device between the specified host's interface and the internal bridge. The vlan-device is based on '8021q' kernel module. - mode 'vlan' has no routed iptables rules but has other common iptables rules It can simplify the work of management apps whose developers want to implement VLan but don't want to introduce OVS into their project. Thank John for his comments in v1. v1 here: https://www.redhat.com/archives/libvir-list/2018-July/msg00331.html since v1: - Change docs/formatnetwork.html.in - Change docs/schemas/network.rng - Add tests/networkxml2* - Other code fixes Besides, I have post two patches followed by John's suggestions. - Replace 'if' type conditions with 'switch' for VIR_NETWORK_FORWARD_* https://www.redhat.com/archives/libvir-list/2018-July/msg01537.html This has been accepted. - Introduce timeout mode for virKModLoad to solve the potential problem of the 'strange delay' when loading '8021q' module https://www.redhat.com/archives/libvir-list/2018-August/msg00605.html This has been rejected and I don't know wether I should continue to solve this problem. Now I just check the INIT process code of '8021q' module and I think this module should not cause delay now. The loading time of '8021q' by virKModLoad on my PC is about 30 milliseconds. Shi Lei (3): add functions: load 8021q module, create/destroy vlan-dev support new forward mode 'vlan' for virtual network tests and docs for new forward mode 'vlan' configure.ac | 6 + docs/formatnetwork.html.in | 27 ++- docs/schemas/network.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/network_conf.c | 24 ++- src/conf/network_conf.h | 1 + src/conf/virnetworkobj.c | 1 + src/esx/esx_network_driver.c | 1 + src/libvirt_private.syms | 4 + src/network/bridge_driver.c | 55 +++++- src/qemu/qemu_process.c | 1 + src/util/virnetdev.c | 203 +++++++++++++++++++++ src/util/virnetdev.h | 18 ++ tests/networkxml2confdata/vlan-network.conf | 16 ++ tests/networkxml2confdata/vlan-network.xml | 13 ++ tests/networkxml2conftest.c | 1 + .../vlan-network-multi-vlan-tag.xml | 11 ++ .../vlan-network-no-forward-dev.xml | 10 + tests/networkxml2xmlin/vlan-network-with-dhcp.xml | 15 ++ tests/networkxml2xmlin/vlan-network.xml | 10 + tests/networkxml2xmlout/vlan-network-with-dhcp.xml | 17 ++ tests/networkxml2xmlout/vlan-network.xml | 12 ++ tests/networkxml2xmltest.c | 5 + 23 files changed, 448 insertions(+), 5 deletions(-) create mode 100644 tests/networkxml2confdata/vlan-network.conf create mode 100644 tests/networkxml2confdata/vlan-network.xml create mode 100644 tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml create mode 100644 tests/networkxml2xmlin/vlan-network-no-forward-dev.xml create mode 100644 tests/networkxml2xmlin/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlin/vlan-network.xml create mode 100644 tests/networkxml2xmlout/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlout/vlan-network.xml -- 2.7.4

Signed-off-by: Shi Lei <shilei.massclouds@gmx.com> --- configure.ac | 6 ++ src/libvirt_private.syms | 4 + src/util/virnetdev.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 18 +++++ 4 files changed, 231 insertions(+) diff --git a/configure.ac b/configure.ac index da940e3..5f2ea12 100644 --- a/configure.ac +++ b/configure.ac @@ -784,6 +784,12 @@ AM_CONDITIONAL([WITH_NODE_DEVICES], [test "$with_nodedev" = "yes"]) dnl GET_VLAN_VID_CMD is required for virNetDevGetVLanID AC_CHECK_DECLS([GET_VLAN_VID_CMD], [], [], [[#include <linux/if_vlan.h>]]) +dnl ADD_VLAN_CMD is required for virNetDevCreateVLanDev +AC_CHECK_DECLS([ADD_VLAN_CMD], [], [], [[#include <linux/if_vlan.h>]]) + +dnl DEL_VLAN_CMD is required for virNetDevDestroyVLanDev +AC_CHECK_DECLS([DEL_VLAN_CMD], [], [], [[#include <linux/if_vlan.h>]]) + # Check for Linux vs. BSD ifreq members AC_CHECK_MEMBERS([struct ifreq.ifr_newname, struct ifreq.ifr_ifindex, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ca4a192..f41fa43 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2267,7 +2267,9 @@ virModuleLoad; # util/virnetdev.h virNetDevAddMulti; +virNetDevCreateVLanDev; virNetDevDelMulti; +virNetDevDestroyVLanDev; virNetDevExists; virNetDevFeatureTypeFromString; virNetDevFeatureTypeToString; @@ -2288,10 +2290,12 @@ virNetDevGetRxFilter; virNetDevGetVirtualFunctionIndex; virNetDevGetVirtualFunctionInfo; virNetDevGetVirtualFunctions; +virNetDevGetVLanDevName; virNetDevGetVLanID; virNetDevIfStateTypeFromString; virNetDevIfStateTypeToString; virNetDevIsVirtualFunction; +virNetDevLoad8021Q; virNetDevPFGetVF; virNetDevReadNetConfig; virNetDevRunEthernetScript; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 8eac419..5425a41 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -43,6 +43,7 @@ # include <linux/sockios.h> # include <linux/if_vlan.h> # define VIR_NETDEV_FAMILY AF_UNIX +# include "virkmod.h" #elif defined(HAVE_STRUCT_IFREQ) && defined(AF_LOCAL) # define VIR_NETDEV_FAMILY AF_LOCAL #else @@ -1054,6 +1055,208 @@ int virNetDevGetVLanID(const char *ifname ATTRIBUTE_UNUSED, #endif /* ! SIOCGIFVLAN */ +#if defined(HAVE_STRUCT_IFREQ) + +# define MODULE_8021Q "8021q" +# define PROC_NET_VLAN_CONFIG "/proc/net/vlan/config" + +static int +controlVlanDev(unsigned int cmd, + const char *ifname, + unsigned int vlanid, + const char *vdname) +{ + int fd; + struct vlan_ioctl_args if_request; + + if (!ifname || strlen(ifname) == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface name not provided")); + return -1; + } + + memset(&if_request, 0, sizeof(struct vlan_ioctl_args)); + if_request.cmd = cmd; + if (cmd == ADD_VLAN_CMD) { + /* for vlan_ioctl_args.devices1[24] */ + if (strlen(ifname) > 24) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Interface name '%s' too long"), + ifname); + return -1; + } + strcpy(if_request.device1, ifname); + if_request.u.VID = vlanid; + } else if (cmd == DEL_VLAN_CMD) { + if (!vdname) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("vlan-device name not provided")); + return -1; + } + /* for vlan_ioctl_args.devices1[24] */ + if (strlen(vdname) > 24) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("vlan-device name '%s' too long"), + vdname); + return -1; + } + strcpy(if_request.device1, vdname); + } else { + virReportSystemError(ENOSYS, + _("unsupported command option: %d"), + cmd); + return -1; + } + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + virReportSystemError(errno, "%s", + _("unable to open VLAN control socket")); + return -1; + } + + if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { + virReportSystemError(errno, "%s", + _("control VLAN device error")); + VIR_FORCE_CLOSE(fd); + return -1; + } + + VIR_FORCE_CLOSE(fd); + return 0; +} + + +/** + * virNetDevGetVLanDevName: + * @ifname: name of interface vlan-device depends on + * @vlanid: VLAN ID + * @vdname: used to return the name of vlan-device + * + * Get the name of the vlan-device + * + * Returns 0 on success, -1 on failure + */ +int +virNetDevGetVLanDevName(const char *ifname, unsigned int vlanid, char **vdname) +{ + if (!ifname || strlen(ifname) == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface name not provided")); + return -1; + } + if (virAsprintf(vdname, "%s.%d", ifname, vlanid) < 0) + return -1; + return 0; +} + + +/** + * virNetDevLoad8021Q: + * + * Load 8021q module (since kernel v2.6) + * + * Returns 0 on success, -1 on failure + */ +int +virNetDevLoad8021Q(void) +{ + if (!virFileExists(PROC_NET_VLAN_CONFIG)) { + VIR_AUTOFREE(char *) errbuf = NULL; + if ((errbuf = virKModLoad(MODULE_8021Q, false))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to load 8021q module")); + return -1; + } + if (!virFileExists(PROC_NET_VLAN_CONFIG)) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("cannot load 8021q module")); + return -1; + } + } + return 0; +} + + +/** + * virNetDevCreateVLanDev: + * @ifname: name of interface we will create vlan-device on + * @vlanid: VLAN ID + * @vdname: used to return the name of vlan-device + * + * Create vlan-device which based on 8021q module. + * + * Returns 0 on success, -1 on failure + */ +int +virNetDevCreateVLanDev(const char *ifname, unsigned int vlanid, char **vdname) +{ + if (controlVlanDev(ADD_VLAN_CMD, ifname, vlanid, NULL) < 0) + return -1; + return virNetDevGetVLanDevName(ifname, vlanid, vdname); +} + + +/** + * virNetDevDestroyVLanDev: + * @ifname: name of interface vlan-device depends on + * @vlanid: VLAN ID + * @vdname: the name of vlan-device + * + * Destroy vlan-device whick has created by virNetDevCreateVLanDev. + */ +void +virNetDevDestroyVLanDev(const char *ifname, + unsigned int vlanid, + const char *vdname) +{ + ignore_value(controlVlanDev(DEL_VLAN_CMD, ifname, vlanid, vdname)); +} + +#else /* !HAVE_STRUCT_IFREQ */ + +int +virNetDevGetVLanDevName(const char *ifname ATTRIBUTE_UNUSED, + unsigned int vlanid ATTRIBUTE_UNUSED, + char **vdname ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get vlan-dev name on this platform")); + return -1; +} + + +int +virNetDevLoad8021Q(void) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to load 8021q module on this platform")); + return -1; +} + + +int +virNetDevCreateVLanDev(const char *ifname ATTRIBUTE_UNUSED, + unsigned int vlanid ATTRIBUTE_UNUSED, + char **vdname ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to create vlan-dev on this platform")); + return -1; +} + + +void +virNetDevDestroyVLanDev(const char *ifname ATTRIBUTE_UNUSED, + unsigned int vlanid ATTRIBUTE_UNUSED, + const char *vdname ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to destroy vlan-dev on this platform")); +} + +#endif /* HAVE_STRUCT_IFREQ */ + + /** * virNetDevValidateConfig: * @ifname: Name of the interface diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 8860ea1..d1fb58e 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -207,6 +207,24 @@ int virNetDevGetIndex(const char *ifname, int *ifindex) int virNetDevGetVLanID(const char *ifname, int *vlanid) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevGetVLanDevName(const char *ifname, + unsigned int vlanid, + char **vdname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; + +int virNetDevLoad8021Q(void) + ATTRIBUTE_RETURN_CHECK; + +int virNetDevCreateVLanDev(const char *ifname, + unsigned int vlanid, + char **vdname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; + +void virNetDevDestroyVLanDev(const char *ifname, + unsigned int vlanid, + const char *vdname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + int virNetDevGetMaster(const char *ifname, char **master) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; -- 2.7.4

Signed-off-by: Shi Lei <shilei.massclouds@gmx.com> --- src/conf/domain_conf.c | 1 + src/conf/network_conf.c | 24 +++++++++++++++++-- src/conf/network_conf.h | 1 + src/conf/virnetworkobj.c | 1 + src/esx/esx_network_driver.c | 1 + src/network/bridge_driver.c | 55 ++++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_process.c | 1 + 7 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 77cc737..0b6d247 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30369,6 +30369,7 @@ virDomainNetResolveActualType(virDomainNetDefPtr iface) case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* for these forward types, the actual net type really *is* * NETWORK; we just keep the info from the portgroup in * iface->data.network.actual diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index c08456b..cb51c7b 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -50,7 +50,7 @@ VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, "none", "nat", "route", "open", "bridge", "private", "vepa", "passthrough", - "hostdev") + "hostdev", "vlan") VIR_ENUM_IMPL(virNetworkBridgeMACTableManager, VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST, @@ -1914,6 +1914,24 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) } break; + case VIR_NETWORK_FORWARD_VLAN: + if (def->forward.nifs != 1 || + strlen(def->forward.ifs[0].device.dev) == 0) { + virReportError(VIR_ERR_XML_ERROR, + _("network '%s' in forward mode 'vlan' requests " + "one and only one interface"), + def->name); + goto error; + } + if (def->vlan.nTags != 1 || def->vlan.tag[0] >= 4096) { + virReportError(VIR_ERR_XML_ERROR, + _("network '%s' in forward mode 'vlan' requests " + "one and only one VLan-Tag"), + def->name); + goto error; + } + break; + case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: @@ -1970,6 +1988,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: break; case VIR_NETWORK_FORWARD_BRIDGE: @@ -1978,7 +1997,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) case VIR_NETWORK_FORWARD_PASSTHROUGH: case VIR_NETWORK_FORWARD_HOSTDEV: virReportError(VIR_ERR_XML_ERROR, - _("mtu size only allowed in open, route, nat, " + _("mtu size only allowed in open, route, nat, vlan " "and isolated mode, not in %s (network '%s')"), virNetworkForwardTypeToString(def->forward.type), def->name); @@ -2494,6 +2513,7 @@ virNetworkDefFormatBuf(virBufferPtr buf, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: hasbridge = true; break; diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 54c8ed1..47bb83e 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -53,6 +53,7 @@ typedef enum { VIR_NETWORK_FORWARD_VEPA, VIR_NETWORK_FORWARD_PASSTHROUGH, VIR_NETWORK_FORWARD_HOSTDEV, + VIR_NETWORK_FORWARD_VLAN, VIR_NETWORK_FORWARD_LAST, } virNetworkForwardType; diff --git a/src/conf/virnetworkobj.c b/src/conf/virnetworkobj.c index b13e5a7..fd5c268 100644 --- a/src/conf/virnetworkobj.c +++ b/src/conf/virnetworkobj.c @@ -1014,6 +1014,7 @@ virNetworkLoadConfig(virNetworkObjListPtr nets, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: if (!def->mac_specified) { virNetworkSetBridgeMacAddr(def); virNetworkSaveConfig(configDir, def); diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 31bceb7..8f91ae9 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -334,6 +334,7 @@ esxNetworkDefineXML(virConnectPtr conn, const char *xml) case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 588b0d1..2e203f5 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -451,6 +451,7 @@ networkUpdateState(virNetworkObjPtr obj, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* If bridge doesn't exist, then mark it inactive */ if (!(def->bridge && virNetDevExists(def->bridge) == 1)) virNetworkObjSetActive(obj, false); @@ -2099,6 +2100,7 @@ networkRefreshDaemonsHelper(virNetworkObjPtr obj, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* Only the three L3 network types that are configured by * libvirt will have a dnsmasq or radvd daemon associated * with them. Here we send a SIGHUP to an existing @@ -2155,6 +2157,7 @@ networkReloadFirewallRulesHelper(virNetworkObjPtr obj, case VIR_NETWORK_FORWARD_NONE: case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: + case VIR_NETWORK_FORWARD_VLAN: /* Only three of the L3 network types that are configured by * libvirt need to have iptables rules reloaded. The 4th L3 * network type, forward='open', doesn't need this because it @@ -2552,6 +2555,29 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver, if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0) goto err5; + if (def->forward.type == VIR_NETWORK_FORWARD_VLAN) { + /* ifs[0].device.dev and vlan.tag[0] have been validated + * in virNetworkDefParseXML + */ + VIR_AUTOFREE(char *) vlanDevName = NULL; + if (virNetDevCreateVLanDev(def->forward.ifs[0].device.dev, def->vlan.tag[0], + &vlanDevName) < 0) + goto err5; + + if (virNetDevBridgeAddPort(def->bridge, vlanDevName) < 0) { + virNetDevDestroyVLanDev(def->forward.ifs[0].device.dev, + def->vlan.tag[0], vlanDevName); + goto err5; + } + + if (virNetDevSetOnline(vlanDevName, true) < 0) { + ignore_value(virNetDevBridgeRemovePort(def->bridge, vlanDevName)); + virNetDevDestroyVLanDev(def->forward.ifs[0].device.dev, + def->vlan.tag[0], vlanDevName); + goto err5; + } + } + VIR_FREE(macTapIfName); VIR_FREE(macMapFile); @@ -2616,6 +2642,17 @@ networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver, pid_t radvdPid; pid_t dnsmasqPid; + if (def->forward.type == VIR_NETWORK_FORWARD_VLAN) { + VIR_AUTOFREE(char *) vlanDevName = NULL; + if (!virNetDevGetVLanDevName(def->forward.ifs[0].device.dev, + def->vlan.tag[0], &vlanDevName)) { + ignore_value(virNetDevSetOnline(vlanDevName, false)); + ignore_value(virNetDevBridgeRemovePort(def->bridge, vlanDevName)); + virNetDevDestroyVLanDev(def->forward.ifs[0].device.dev, + def->vlan.tag[0], vlanDevName); + } + } + if (def->bandwidth) virNetDevBandwidthClear(def->bridge); @@ -2759,6 +2796,7 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* by definition these will never be encountered here */ break; @@ -2861,6 +2899,7 @@ networkStartNetwork(virNetworkDriverStatePtr driver, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: if (networkStartNetworkVirtual(driver, obj) < 0) goto cleanup; break; @@ -2948,6 +2987,7 @@ networkShutdownNetwork(virNetworkDriverStatePtr driver, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: ret = networkShutdownNetworkVirtual(driver, obj); break; @@ -3332,6 +3372,7 @@ networkValidate(virNetworkDriverStatePtr driver, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* if no bridge name was given in the config, find a name * unused by any other libvirt networks and assign it. */ @@ -3510,11 +3551,12 @@ networkValidate(virNetworkDriverStatePtr driver, /* The only type of networks that currently support transparent * vlan configuration are those using hostdev sr-iov devices from - * a pool, and those using an Open vSwitch bridge. + * a pool, and those using an Open vSwitch bridge or based on 8021q. */ vlanAllowed = (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV || def->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH || + def->forward.type == VIR_NETWORK_FORWARD_VLAN || (def->forward.type == VIR_NETWORK_FORWARD_BRIDGE && def->virtPortProfile && def->virtPortProfile->virtPortType @@ -3596,6 +3638,11 @@ networkValidate(virNetworkDriverStatePtr driver, } } } + + if (def->forward.type == VIR_NETWORK_FORWARD_VLAN) { + if (virNetDevLoad8021Q() < 0) + return -1; + } return 0; } @@ -3825,6 +3872,7 @@ networkUpdate(virNetworkPtr net, case VIR_NETWORK_FORWARD_NONE: case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: + case VIR_NETWORK_FORWARD_VLAN: switch (section) { case VIR_NETWORK_SECTION_FORWARD: case VIR_NETWORK_SECTION_FORWARD_INTERFACE: @@ -4531,6 +4579,7 @@ networkAllocateActualDevice(virDomainDefPtr dom, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: /* for these forward types, the actual net type really *is* * NETWORK; we just keep the info from the portgroup in * iface->data.network.actual @@ -4792,7 +4841,8 @@ networkAllocateActualDevice(virDomainDefPtr dom, * mode) and openvswitch bridges. Otherwise log an error and * fail */ - if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV || + if (!(netdef->forward.type == VIR_NETWORK_FORWARD_VLAN || + actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV || (actualType == VIR_DOMAIN_NET_TYPE_DIRECT && virDomainNetGetActualDirectMode(iface) == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) || @@ -5133,6 +5183,7 @@ networkReleaseActualDevice(virDomainDefPtr dom, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: if (iface->data.network.actual && networkUnplugBandwidth(obj, iface) < 0) goto error; break; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 02fdc55..ae725a8 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4550,6 +4550,7 @@ qemuProcessGetNetworkAddress(const char *netname, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: + case VIR_NETWORK_FORWARD_VLAN: ipdef = virNetworkDefGetIPByIndex(netdef, AF_UNSPEC, 0); if (!ipdef) { virReportError(VIR_ERR_INTERNAL_ERROR, -- 2.7.4

Signed-off-by: Shi Lei <shilei.massclouds@gmx.com> --- docs/formatnetwork.html.in | 27 +++++++++++++++++++++- docs/schemas/network.rng | 1 + tests/networkxml2confdata/vlan-network.conf | 16 +++++++++++++ tests/networkxml2confdata/vlan-network.xml | 13 +++++++++++ tests/networkxml2conftest.c | 1 + .../vlan-network-multi-vlan-tag.xml | 11 +++++++++ .../vlan-network-no-forward-dev.xml | 10 ++++++++ tests/networkxml2xmlin/vlan-network-with-dhcp.xml | 15 ++++++++++++ tests/networkxml2xmlin/vlan-network.xml | 10 ++++++++ tests/networkxml2xmlout/vlan-network-with-dhcp.xml | 17 ++++++++++++++ tests/networkxml2xmlout/vlan-network.xml | 12 ++++++++++ tests/networkxml2xmltest.c | 5 ++++ 12 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tests/networkxml2confdata/vlan-network.conf create mode 100644 tests/networkxml2confdata/vlan-network.xml create mode 100644 tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml create mode 100644 tests/networkxml2xmlin/vlan-network-no-forward-dev.xml create mode 100644 tests/networkxml2xmlin/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlin/vlan-network.xml create mode 100644 tests/networkxml2xmlout/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlout/vlan-network.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 363a72b..294256c 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -156,7 +156,7 @@ <dt><code>mtu</code></dt> <dd> - The <code>size</code> attribute of the <code>mtu></code> + The <code>size</code> attribute of the <code>mtu</code> element specifies the Maximum Transmission Unit (MTU) for the network. <span class="since">Since 3.1.0</span>. In the case of a libvirt-managed network (one with forward mode @@ -299,6 +299,31 @@ <span class="since">Since 2.2.0</span> </dd> + <dt><code>vlan</code></dt> + <dd> + All guests linked to this network will belong to a VLan. + Guests communicate with each other directly and communicate + with outside network via this network. Egress traffic from + this network will be tagged transparently by the VLan-Tag; + ingress traffic will be untagged and transport into this + network only if traffic has the same VLan-Tag, or be dropped. + The <code>dev</code> attribute must be set to specify the + host's interface which forwards traffice between this network + and outside. The <code>vlan</code> element and its <code>tag</code> + element must be one and only, and the <code>id</code> attribute + specifies the tag of this VLan. The <code>bridge</code> element + can be ignored since it is a internal bridge. This network + supports <code>ip</code> and <code>dhcp</code>. + <span class="since">Since 4.7.0</span> + <pre> +... + <forward mode='vlan' dev='eth1'/> + <vlan> + <tag id="20"/> + </vlan> +...</pre> + </dd> + <dt><code>bridge</code></dt> <dd> This network describes either 1) an existing host bridge diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index f37c422..046f6dd 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -114,6 +114,7 @@ <value>private</value> <value>vepa</value> <value>hostdev</value> + <value>vlan</value> </choice> </attribute> </optional> diff --git a/tests/networkxml2confdata/vlan-network.conf b/tests/networkxml2confdata/vlan-network.conf new file mode 100644 index 0000000..5d1d091 --- /dev/null +++ b/tests/networkxml2confdata/vlan-network.conf @@ -0,0 +1,16 @@ +##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE +##OVERWRITTEN AND LOST. Changes to this configuration should be made using: +## virsh net-edit vlanB +## or other application using the libvirt API. +## +## dnsmasq conf file created by libvirt +strict-order +except-interface=lo +bind-dynamic +interface=virbr1 +dhcp-range=192.168.126.60,192.168.126.69 +dhcp-no-override +dhcp-authoritative +dhcp-lease-max=10 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/vlanB.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/vlanB.addnhosts diff --git a/tests/networkxml2confdata/vlan-network.xml b/tests/networkxml2confdata/vlan-network.xml new file mode 100644 index 0000000..0faa7bb --- /dev/null +++ b/tests/networkxml2confdata/vlan-network.xml @@ -0,0 +1,13 @@ +<network> + <name>vlanB</name> + <forward mode="vlan" dev="p5p1"/> + <bridge name='virbr1'/> + <vlan> + <tag id="20"/> + </vlan> + <ip address="192.168.126.2" netmask="255.255.255.0"> + <dhcp> + <range start="192.168.126.60" end="192.168.126.69"/> + </dhcp> + </ip> +</network> diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index 8e7751e..d106c6a 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -144,6 +144,7 @@ mymain(void) DO_TEST("dhcp6-nat-network", dhcpv6); DO_TEST("dhcp6host-routed-network", dhcpv6); DO_TEST("ptr-domains-auto", dhcpv6); + DO_TEST("vlan-network", full); virObjectUnref(dhcpv6); virObjectUnref(full); diff --git a/tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml b/tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml new file mode 100644 index 0000000..328e9a4 --- /dev/null +++ b/tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml @@ -0,0 +1,11 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward mode="vlan" dev="eth1"/> + <bridge name='virbr1'/> + <mac address='12:34:56:78:9A:BC'/> + <vlan> + <tag id="20"/> + <tag id="30"/> + </vlan> +</network> diff --git a/tests/networkxml2xmlin/vlan-network-no-forward-dev.xml b/tests/networkxml2xmlin/vlan-network-no-forward-dev.xml new file mode 100644 index 0000000..c8384cf --- /dev/null +++ b/tests/networkxml2xmlin/vlan-network-no-forward-dev.xml @@ -0,0 +1,10 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward mode="vlan"/> + <bridge name='virbr1'/> + <mac address='12:34:56:78:9A:BC'/> + <vlan> + <tag id="20"/> + </vlan> +</network> diff --git a/tests/networkxml2xmlin/vlan-network-with-dhcp.xml b/tests/networkxml2xmlin/vlan-network-with-dhcp.xml new file mode 100644 index 0000000..e51eaeb --- /dev/null +++ b/tests/networkxml2xmlin/vlan-network-with-dhcp.xml @@ -0,0 +1,15 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward mode="vlan" dev="eth1"/> + <bridge name='virbr1'/> + <mac address='12:34:56:78:9A:BC'/> + <vlan> + <tag id="20"/> + </vlan> + <ip address="192.168.126.2" netmask="255.255.255.0"> + <dhcp> + <range start="192.168.126.60" end="192.168.126.69"/> + </dhcp> + </ip> +</network> diff --git a/tests/networkxml2xmlin/vlan-network.xml b/tests/networkxml2xmlin/vlan-network.xml new file mode 100644 index 0000000..3bf075a --- /dev/null +++ b/tests/networkxml2xmlin/vlan-network.xml @@ -0,0 +1,10 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward mode="vlan" dev="eth1"/> + <bridge name='virbr1'/> + <mac address='12:34:56:78:9A:BC'/> + <vlan> + <tag id="20"/> + </vlan> +</network> diff --git a/tests/networkxml2xmlout/vlan-network-with-dhcp.xml b/tests/networkxml2xmlout/vlan-network-with-dhcp.xml new file mode 100644 index 0000000..58ab96d --- /dev/null +++ b/tests/networkxml2xmlout/vlan-network-with-dhcp.xml @@ -0,0 +1,17 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward dev='eth1' mode='vlan'> + <interface dev='eth1'/> + </forward> + <bridge name='virbr1' stp='on' delay='0'/> + <mac address='12:34:56:78:9a:bc'/> + <vlan> + <tag id='20'/> + </vlan> + <ip address='192.168.126.2' netmask='255.255.255.0'> + <dhcp> + <range start='192.168.126.60' end='192.168.126.69'/> + </dhcp> + </ip> +</network> diff --git a/tests/networkxml2xmlout/vlan-network.xml b/tests/networkxml2xmlout/vlan-network.xml new file mode 100644 index 0000000..e19ce49 --- /dev/null +++ b/tests/networkxml2xmlout/vlan-network.xml @@ -0,0 +1,12 @@ +<network> + <name>vlanB</name> + <uuid>d29b765a-896c-450c-b94a-1b6b21c340db</uuid> + <forward dev='eth1' mode='vlan'> + <interface dev='eth1'/> + </forward> + <bridge name='virbr1' stp='on' delay='0'/> + <mac address='12:34:56:78:9a:bc'/> + <vlan> + <tag id='20'/> + </vlan> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index eb7db76..72957c7 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -44,6 +44,7 @@ testCompareXMLToXMLFiles(const char *inxml, const char *outxml, result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT; goto cleanup; } + if (expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT) goto cleanup; @@ -160,6 +161,10 @@ mymain(void) DO_TEST_PARSE_ERROR("passthrough-duplicate"); DO_TEST("metadata"); DO_TEST("set-mtu"); + DO_TEST("vlan-network"); + DO_TEST("vlan-network-with-dhcp"); + DO_TEST_PARSE_ERROR("vlan-network-no-forward-dev"); + DO_TEST_PARSE_ERROR("vlan-network-multi-vlan-tag"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.7.4

On 08/14/2018 03:00 AM, Shi Lei wrote:
Hi, everyone!
This patch supports VLan by '8021q' kernel module other than by OVS. The way of '8021q' is simpler and more robust.
Mode 'vlan' is like mode 'route' except these major differences: - mode 'vlan' inserts a vlan-device between the specified host's interface and the internal bridge. The vlan-device is based on '8021q' kernel module. - mode 'vlan' has no routed iptables rules but has other common iptables rules
It can simplify the work of management apps whose developers want to implement VLan but don't want to introduce OVS into their project.
First off - apologies no one has even looked at your v2 yet. If after a week no one looks, please feel free to just ping the cover letter and usually that helps get someone to look or direct at the right person. August is a month where many take vacations so series do get lost in the volume of upstream postings at times. Generally for network things like this I defer to Laine as he understand the comings and goings in that space much more so than I do. Considering your other changes, could you just update this series with all the changes to use switch's instead of if/then logic and repost one you ensure that for each patch you can 'make check syntax-check'. I have a feeling patch3 just merges into patch2. Some of the text you put in here could be used to beef up the commit messages for each patch which are too sparse... The commit message text should describe the change or addition and not just be a single line header. I think you would need to add a docs/news.xml article. But wait until 4.8.0 opens in order to repost. Should be soon anyway. Tks, John
Thank John for his comments in v1. v1 here: https://www.redhat.com/archives/libvir-list/2018-July/msg00331.html
since v1: - Change docs/formatnetwork.html.in - Change docs/schemas/network.rng - Add tests/networkxml2* - Other code fixes
Besides, I have post two patches followed by John's suggestions. - Replace 'if' type conditions with 'switch' for VIR_NETWORK_FORWARD_* https://www.redhat.com/archives/libvir-list/2018-July/msg01537.html This has been accepted.
- Introduce timeout mode for virKModLoad to solve the potential problem of the 'strange delay' when loading '8021q' module https://www.redhat.com/archives/libvir-list/2018-August/msg00605.html This has been rejected and I don't know wether I should continue to solve this problem. Now I just check the INIT process code of '8021q' module and I think this module should not cause delay now. The loading time of '8021q' by virKModLoad on my PC is about 30 milliseconds.
Shi Lei (3): add functions: load 8021q module, create/destroy vlan-dev support new forward mode 'vlan' for virtual network tests and docs for new forward mode 'vlan'
configure.ac | 6 + docs/formatnetwork.html.in | 27 ++- docs/schemas/network.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/network_conf.c | 24 ++- src/conf/network_conf.h | 1 + src/conf/virnetworkobj.c | 1 + src/esx/esx_network_driver.c | 1 + src/libvirt_private.syms | 4 + src/network/bridge_driver.c | 55 +++++- src/qemu/qemu_process.c | 1 + src/util/virnetdev.c | 203 +++++++++++++++++++++ src/util/virnetdev.h | 18 ++ tests/networkxml2confdata/vlan-network.conf | 16 ++ tests/networkxml2confdata/vlan-network.xml | 13 ++ tests/networkxml2conftest.c | 1 + .../vlan-network-multi-vlan-tag.xml | 11 ++ .../vlan-network-no-forward-dev.xml | 10 + tests/networkxml2xmlin/vlan-network-with-dhcp.xml | 15 ++ tests/networkxml2xmlin/vlan-network.xml | 10 + tests/networkxml2xmlout/vlan-network-with-dhcp.xml | 17 ++ tests/networkxml2xmlout/vlan-network.xml | 12 ++ tests/networkxml2xmltest.c | 5 + 23 files changed, 448 insertions(+), 5 deletions(-) create mode 100644 tests/networkxml2confdata/vlan-network.conf create mode 100644 tests/networkxml2confdata/vlan-network.xml create mode 100644 tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml create mode 100644 tests/networkxml2xmlin/vlan-network-no-forward-dev.xml create mode 100644 tests/networkxml2xmlin/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlin/vlan-network.xml create mode 100644 tests/networkxml2xmlout/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlout/vlan-network.xml

On 2018-09-01 at 20:13, John Ferlan wrote:
On 08/14/2018 03:00 AM, Shi Lei wrote:
Hi, everyone!
This patch supports VLan by '8021q' kernel module other than by OVS. The way of '8021q' is simpler and more robust.
Mode 'vlan' is like mode 'route' except these major differences: - mode 'vlan' inserts a vlan-device between the specified host's interface and the internal bridge. The vlan-device is based on '8021q' kernel module. - mode 'vlan' has no routed iptables rules but has other common iptables rules
It can simplify the work of management apps whose developers want to implement VLan but don't want to introduce OVS into their project.
First off - apologies no one has even looked at your v2 yet. If after a week no one looks, please feel free to just ping the cover letter and usually that helps get someone to look or direct at the right person. August is a month where many take vacations so series do get lost in the volume of upstream postings at times. Generally for network things like this I defer to Laine as he understand the comings and goings in that space much more so than I do.
I see.
Considering your other changes, could you just update this series with all the changes to use switch's instead of if/then logic and repost one you ensure that for each patch you can 'make check syntax-check'. I have a feeling patch3 just merges into patch2.
Okay.
Some of the text you put in here could be used to beef up the commit messages for each patch which are too sparse... The commit message text should describe the change or addition and not just be a single line header.
Okay. I'll rewrite them.
I think you would need to add a docs/news.xml article. But wait until 4.8.0 opens in order to repost. Should be soon anyway.
Okay.
Tks,
John
Thanks for your directions. And I will wait and post v3 until v4.8.0 opens. :-) Shi Lei
Thank John for his comments in v1. v1 here: https://www.redhat.com/archives/libvir-list/2018-July/msg00331.html
since v1: - Change docs/formatnetwork.html.in - Change docs/schemas/network.rng - Add tests/networkxml2* - Other code fixes
Besides, I have post two patches followed by John's suggestions. - Replace 'if' type conditions with 'switch' for VIR_NETWORK_FORWARD_* https://www.redhat.com/archives/libvir-list/2018-July/msg01537.html This has been accepted.
- Introduce timeout mode for virKModLoad to solve the potential problem of the 'strange delay' when loading '8021q' module https://www.redhat.com/archives/libvir-list/2018-August/msg00605.html This has been rejected and I don't know wether I should continue to solve this problem. Now I just check the INIT process code of '8021q' module and I think this module should not cause delay now. The loading time of '8021q' by virKModLoad on my PC is about 30 milliseconds.
Shi Lei (3): add functions: load 8021q module, create/destroy vlan-dev support new forward mode 'vlan' for virtual network tests and docs for new forward mode 'vlan'
configure.ac | 6 + docs/formatnetwork.html.in | 27 ++- docs/schemas/network.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/network_conf.c | 24 ++- src/conf/network_conf.h | 1 + src/conf/virnetworkobj.c | 1 + src/esx/esx_network_driver.c | 1 + src/libvirt_private.syms | 4 + src/network/bridge_driver.c | 55 +++++- src/qemu/qemu_process.c | 1 + src/util/virnetdev.c | 203 +++++++++++++++++++++ src/util/virnetdev.h | 18 ++ tests/networkxml2confdata/vlan-network.conf | 16 ++ tests/networkxml2confdata/vlan-network.xml | 13 ++ tests/networkxml2conftest.c | 1 + .../vlan-network-multi-vlan-tag.xml | 11 ++ .../vlan-network-no-forward-dev.xml | 10 + tests/networkxml2xmlin/vlan-network-with-dhcp.xml | 15 ++ tests/networkxml2xmlin/vlan-network.xml | 10 + tests/networkxml2xmlout/vlan-network-with-dhcp.xml | 17 ++ tests/networkxml2xmlout/vlan-network.xml | 12 ++ tests/networkxml2xmltest.c | 5 + 23 files changed, 448 insertions(+), 5 deletions(-) create mode 100644 tests/networkxml2confdata/vlan-network.conf create mode 100644 tests/networkxml2confdata/vlan-network.xml create mode 100644 tests/networkxml2xmlin/vlan-network-multi-vlan-tag.xml create mode 100644 tests/networkxml2xmlin/vlan-network-no-forward-dev.xml create mode 100644 tests/networkxml2xmlin/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlin/vlan-network.xml create mode 100644 tests/networkxml2xmlout/vlan-network-with-dhcp.xml create mode 100644 tests/networkxml2xmlout/vlan-network.xml
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
participants (3)
-
John Ferlan
-
Shi Lei
-
Shi Lei