[PATCH 0/5] Add "support" for VMWare Distributed Switch

Previously (but still in this release) such interfaces were represented as dummy ones, but hopefully we can properly represent them still in the same release. Martin Kletzander (5): tests: Fix vmx/xml filenames conf: Rewrite virNetDevVPortProfileCopy vmx: Require networkName for bridged and custom NICs conf, docs, schemas: Add support for interface type vds vmx: Add support for VDS interface docs/formatdomain.rst | 30 ++++++-- src/ch/ch_monitor.c | 1 + src/conf/domain_conf.c | 73 ++++++++++++++++-- src/conf/domain_conf.h | 7 ++ src/conf/netdev_bandwidth_conf.c | 1 + src/conf/schemas/domaincommon.rng | 23 ++++++ src/libxl/libxl_conf.c | 1 + src/libxl/xen_common.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_driver.c | 3 + src/lxc/lxc_process.c | 2 + src/qemu/qemu_command.c | 4 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_hotplug.c | 3 + src/qemu/qemu_interface.c | 2 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 1 + src/util/virnetdevvportprofile.c | 18 +++-- src/util/virnetdevvportprofile.h | 5 +- src/vmx/vmx.c | 77 +++++++++++++++---- ...unmanaged-nodev.vmx => ethernet-dummy.vmx} | 0 ...unmanaged-nodev.xml => ethernet-dummy.xml} | 0 tests/vmx2xmldata/ethernet-vds.vmx | 11 +++ tests/vmx2xmldata/ethernet-vds.xml | 24 ++++++ tests/vmx2xmltest.c | 3 +- ...d-nodev.vmx => xml2vmx-ethernet-dummy.vmx} | 0 ...d-nodev.xml => xml2vmx-ethernet-dummy.xml} | 0 tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx | 18 +++++ tests/xml2vmxdata/xml2vmx-ethernet-vds.xml | 15 ++++ tests/xml2vmxtest.c | 3 +- tools/virsh-domain.c | 1 + 31 files changed, 292 insertions(+), 39 deletions(-) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.vmx => ethernet-dummy.vmx} (100%) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.xml => ethernet-dummy.xml} (100%) create mode 100644 tests/vmx2xmldata/ethernet-vds.vmx create mode 100644 tests/vmx2xmldata/ethernet-vds.xml rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.vmx => xml2vmx-ethernet-dummy.vmx} (100%) rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.xml => xml2vmx-ethernet-dummy.xml} (100%) create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.xml -- 2.37.2

Commit 70768cda9740 added a functionality that was previously (in an unsubmitted version of the commit) represented differently in the XML, but the filenames kept the old name. Fix the name so they are not misleading. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- .../{ethernet-unmanaged-nodev.vmx => ethernet-dummy.vmx} | 0 .../{ethernet-unmanaged-nodev.xml => ethernet-dummy.xml} | 0 tests/vmx2xmltest.c | 2 +- ...-ethernet-unmanaged-nodev.vmx => xml2vmx-ethernet-dummy.vmx} | 0 ...-ethernet-unmanaged-nodev.xml => xml2vmx-ethernet-dummy.xml} | 0 tests/xml2vmxtest.c | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.vmx => ethernet-dummy.vmx} (100%) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.xml => ethernet-dummy.xml} (100%) rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.vmx => xml2vmx-ethernet-dummy.vmx} (100%) rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.xml => xml2vmx-ethernet-dummy.xml} (100%) diff --git a/tests/vmx2xmldata/ethernet-unmanaged-nodev.vmx b/tests/vmx2xmldata/ethernet-dummy.vmx similarity index 100% rename from tests/vmx2xmldata/ethernet-unmanaged-nodev.vmx rename to tests/vmx2xmldata/ethernet-dummy.vmx diff --git a/tests/vmx2xmldata/ethernet-unmanaged-nodev.xml b/tests/vmx2xmldata/ethernet-dummy.xml similarity index 100% rename from tests/vmx2xmldata/ethernet-unmanaged-nodev.xml rename to tests/vmx2xmldata/ethernet-dummy.xml diff --git a/tests/vmx2xmltest.c b/tests/vmx2xmltest.c index e08079512b53..3ab39148e0a4 100644 --- a/tests/vmx2xmltest.c +++ b/tests/vmx2xmltest.c @@ -236,7 +236,7 @@ mymain(void) DO_TEST("ethernet-static"); DO_TEST("ethernet-vpx"); DO_TEST("ethernet-other"); - DO_TEST("ethernet-unmanaged-nodev"); + DO_TEST("ethernet-dummy"); DO_TEST("serial-file"); DO_TEST("serial-device"); diff --git a/tests/xml2vmxdata/xml2vmx-ethernet-unmanaged-nodev.vmx b/tests/xml2vmxdata/xml2vmx-ethernet-dummy.vmx similarity index 100% rename from tests/xml2vmxdata/xml2vmx-ethernet-unmanaged-nodev.vmx rename to tests/xml2vmxdata/xml2vmx-ethernet-dummy.vmx diff --git a/tests/xml2vmxdata/xml2vmx-ethernet-unmanaged-nodev.xml b/tests/xml2vmxdata/xml2vmx-ethernet-dummy.xml similarity index 100% rename from tests/xml2vmxdata/xml2vmx-ethernet-unmanaged-nodev.xml rename to tests/xml2vmxdata/xml2vmx-ethernet-dummy.xml diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 0ea213d5d5cd..7723c1efabdd 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -225,7 +225,7 @@ mymain(void) DO_TEST("ethernet-other", "ethernet-other", 4); DO_TEST("ethernet-mac-type", "ethernet-mac-type", 4); - DO_TEST("ethernet-unmanaged-nodev", "ethernet-unmanaged-nodev", 4); + DO_TEST("ethernet-dummy", "ethernet-dummy", 4); DO_TEST("serial-file", "serial-file", 4); DO_TEST("serial-device", "serial-device", 4); -- 2.37.2

This makes it nicer to use as since it cannot fail shortens the usage in all callers. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/conf/domain_conf.c | 9 +++------ src/util/virnetdevvportprofile.c | 18 ++++++++++-------- src/util/virnetdevvportprofile.h | 5 +++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7764b1054d6f..0cfbe22dc099 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -29348,8 +29348,7 @@ virDomainNetDefToNetworkPort(virDomainDef *dom, memcpy(&port->mac, &iface->mac, VIR_MAC_BUFLEN); - if (virNetDevVPortProfileCopy(&port->virtPortProfile, iface->virtPortProfile) < 0) - return NULL; + port->virtPortProfile = virNetDevVPortProfileCopy(iface->virtPortProfile); if (virNetDevBandwidthCopy(&port->bandwidth, iface->bandwidth) < 0) return NULL; @@ -29448,8 +29447,7 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, goto error; } - if (virNetDevVPortProfileCopy(&actual->virtPortProfile, port->virtPortProfile) < 0) - goto error; + actual->virtPortProfile = virNetDevVPortProfileCopy(port->virtPortProfile); if (virNetDevBandwidthCopy(&actual->bandwidth, port->bandwidth) < 0) goto error; @@ -29589,8 +29587,7 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, return NULL; } - if (virNetDevVPortProfileCopy(&port->virtPortProfile, actual->virtPortProfile) < 0) - return NULL; + port->virtPortProfile = virNetDevVPortProfileCopy(actual->virtPortProfile); if (virNetDevBandwidthCopy(&port->bandwidth, actual->bandwidth) < 0) return NULL; diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index 88c34879525e..ae23f795b25a 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -122,16 +122,18 @@ virNetDevVPortProfileEqual(const virNetDevVPortProfile *a, const virNetDevVPortP } -int virNetDevVPortProfileCopy(virNetDevVPortProfile **dst, const virNetDevVPortProfile *src) +virNetDevVPortProfile * +virNetDevVPortProfileCopy(const virNetDevVPortProfile *src) { - if (!src) { - *dst = NULL; - return 0; - } + virNetDevVPortProfile *ret = NULL; - *dst = g_new0(virNetDevVPortProfile, 1); - memcpy(*dst, src, sizeof(*src)); - return 0; + if (!src) + return NULL; + + ret = g_new0(virNetDevVPortProfile, 1); + memcpy(ret, src, sizeof(*ret)); + + return ret; } diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index e7a93e23a4f5..600b2093c507 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -77,8 +77,9 @@ struct _virNetDevVPortProfile { bool virNetDevVPortProfileEqual(const virNetDevVPortProfile *a, const virNetDevVPortProfile *b); -int virNetDevVPortProfileCopy(virNetDevVPortProfile **dst, - const virNetDevVPortProfile *src); + +virNetDevVPortProfile * +virNetDevVPortProfileCopy(const virNetDevVPortProfile *src); int virNetDevVPortProfileCheckComplete(virNetDevVPortProfile *virtport, bool generateMissing); -- 2.37.2

On Wed, Aug 17, 2022 at 02:50:37PM +0200, Martin Kletzander wrote:
This makes it nicer to use as since it cannot fail shortens the usage in all callers.
This is unrelated to this series and can be dropped, it was a part of previous implementation that got scratched.

Commit 70768cda9740 marked this particular config string optional, but forgot that two of the interface types still require this name to exist. Mark it as optional only if there is no connectionType. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 49eef12e3ea7..7b705b895ed1 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -2826,7 +2826,7 @@ virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def) STRCASEEQ(connectionType, "bridged") || STRCASEEQ(connectionType, "custom")) { if (virVMXGetConfigString(conf, networkName_name, &networkName, - true) < 0) + connectionType == NULL) < 0) goto cleanup; } -- 2.37.2

This represents an interface connected to a VMWare Distributed Switch, previously obscured as a dummy interface. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.rst | 30 +++++++++++---- src/ch/ch_monitor.c | 1 + src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 7 ++++ src/conf/netdev_bandwidth_conf.c | 1 + src/conf/schemas/domaincommon.rng | 23 +++++++++++ src/libxl/libxl_conf.c | 1 + src/libxl/xen_common.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_driver.c | 3 ++ src/lxc/lxc_process.c | 2 + src/qemu/qemu_command.c | 4 ++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_hotplug.c | 3 ++ src/qemu/qemu_interface.c | 2 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 1 + src/vmx/vmx.c | 1 + tools/virsh-domain.c | 1 + 19 files changed, 141 insertions(+), 8 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index ed0d9c19593b..3a8aa96fdc0a 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -5244,22 +5244,36 @@ Dummy network interface ^^^^^^^^^^^^^^^^^^^^^^^ An unconnected network interface sounds pretty pointless, but can show up for -example with VMWare when libvirt does not have any more information to provide. -Two such scenarios are currently known: +example with VMWare without any specified network to be connected to. +:since:`Since 8.7.0` -1) network interface exists, but is not connected to any existing network -2) the interface is connected to something known as VMWare Distributed Switch +:: + + ... + <devices> + <interface type='dummy'> + <mac address='52:54:00:22:c9:42'/> + </interface> + </devices> + ... -The difference between these two is not (yet?) discoverable by libvirt, so at -least the information gathered from the hypervisor is provided in the -element. :since:`Since 8.7.0` +VMWare Distributed Switch +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Interface can be connected to VMWare Distributed Switch, but since libvirt +cannot provide information about that architecture, the information presented +here is only what can be gathered from the VM configuration. VMs with this +interface type can be created, so that editing of the XML works properly, +however libvirt cannot guarantee that any changes in these parameters will be +valid in the hypervisor. :since:`Since 8.7.0` :: ... <devices> - <interface type='dummy'> + <interface type='vds'> <mac address='52:54:00:22:c9:42'/> + <source switchid='12345678-1234-1234-1234-123456789abc' portid='6' portgroupid='pg-4321' connectionid='12345'/> </interface> </devices> ... diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 67ca4a7a0dcd..03f051edf67e 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -302,6 +302,7 @@ virCHMonitorBuildNetJson(virJSONValue *nets, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: default: virReportEnumRangeError(virDomainNetType, netType); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 0cfbe22dc099..2fc94b40efe2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -574,6 +574,7 @@ VIR_ENUM_IMPL(virDomainNet, "udp", "vdpa", "dummy", + "vds", ); VIR_ENUM_IMPL(virDomainNetModel, @@ -2497,6 +2498,7 @@ virDomainActualNetDefFree(virDomainActualNetDef *def) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -2621,6 +2623,10 @@ virDomainNetDefFree(virDomainNetDef *def) virDomainHostdevDefClear(&def->data.hostdev.def); break; + case VIR_DOMAIN_NET_TYPE_VDS: + g_free(def->data.vds.portgroup_id); + break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY: @@ -8899,6 +8905,8 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, g_autofree char *vhost_path = NULL; g_autofree char *tap = NULL; g_autofree char *vhost = NULL; + g_autofree char *switchid = NULL; + g_autofree char *connectionid = NULL; const char *prefix = xmlopt ? xmlopt->config.netPrefix : NULL; if (!(def = virDomainNetDefNew(xmlopt))) @@ -8932,6 +8940,13 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, portid = virXMLPropString(source_node, "portid"); } + if (def->type == VIR_DOMAIN_NET_TYPE_VDS) { + switchid = virXMLPropString(source_node, "switchid"); + portid = virXMLPropString(source_node, "portid"); + portgroup = virXMLPropString(source_node, "portgroupid"); + connectionid = virXMLPropString(source_node, "connectionid"); + } + if (def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) internal = virXMLPropString(source_node, "name"); @@ -9313,6 +9328,36 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, } break; + case VIR_DOMAIN_NET_TYPE_VDS: + if (!switchid) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing source switchid for interface type '%s'"), + virDomainNetTypeToString(def->type)); + goto error; + } + + if (virUUIDParse(switchid, def->data.vds.switch_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse switchid '%s'"), switchid); + goto error; + } + + if (virStrToLong_ll(portid, NULL, 0, &def->data.vds.port_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse portid '%s'"), portid); + goto error; + } + + if (virStrToLong_ll(connectionid, NULL, 0, &def->data.vds.connection_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse connectionid '%s'"), connectionid); + goto error; + } + + def->data.vds.portgroup_id = g_steal_pointer(&portgroup); + + break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY: @@ -9495,6 +9540,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_VDPA: break; case VIR_DOMAIN_NET_TYPE_LAST: @@ -23683,7 +23729,21 @@ virDomainNetDefFormat(virBuffer *buf, def->data.vdpa.devicepath); sourceLines++; } + break; + + case VIR_DOMAIN_NET_TYPE_VDS: { + char switchidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(def->data.vds.switch_id, switchidstr); + virBufferEscapeString(buf, "<source switchid='%s'", switchidstr); + virBufferAsprintf(buf, " portid='%lld'", def->data.vds.port_id); + virBufferEscapeString(buf, " portgroupid='%s'", def->data.vds.portgroup_id); + virBufferAsprintf(buf, " connectionid='%lld'", def->data.vds.connection_id); + + sourceLines++; + break; + } case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY: @@ -28303,6 +28363,7 @@ virDomainNetGetActualVirtPortProfile(const virDomainNetDef *iface) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -28317,6 +28378,7 @@ virDomainNetGetActualVirtPortProfile(const virDomainNetDef *iface) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: default: return NULL; @@ -29314,6 +29376,7 @@ virDomainNetTypeSharesHostView(const virDomainNetDef *net) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -29576,6 +29639,7 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unexpected network port type %s"), virDomainNetTypeToString(virDomainNetGetActualType(iface))); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7b81acf5db3b..a1f6cf7a6fd0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -940,6 +940,7 @@ typedef enum { VIR_DOMAIN_NET_TYPE_UDP, VIR_DOMAIN_NET_TYPE_VDPA, VIR_DOMAIN_NET_TYPE_DUMMY, + VIR_DOMAIN_NET_TYPE_VDS, VIR_DOMAIN_NET_TYPE_LAST } virDomainNetType; @@ -1133,6 +1134,12 @@ struct _virDomainNetDef { struct { virDomainHostdevDef def; } hostdev; + struct { + unsigned char switch_id[VIR_UUID_BUFLEN]; + char *portgroup_id; + long long port_id; + long long connection_id; + } vds; } data; /* virtPortProfile is used by network/bridge/direct/hostdev */ virNetDevVPortProfile *virtPortProfile; diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c index 58d166901a8c..b1ebfea6ddd7 100644 --- a/src/conf/netdev_bandwidth_conf.c +++ b/src/conf/netdev_bandwidth_conf.c @@ -296,6 +296,7 @@ bool virNetDevSupportsBandwidth(virDomainNetType type) case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5d530f957b0d..7f6ea1d8887d 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -3440,6 +3440,29 @@ <ref name="interface-options"/> </group> + <group> + <attribute name="type"> + <value>vds</value> + </attribute> + <interleave> + <element name="source"> + <attribute name="switchid"> + <ref name="UUID"/> + </attribute> + <attribute name="portid"> + <data type="long"/> + </attribute> + <attribute name="portgroupid"> + <data type="string"/> + </attribute> + <attribute name="connectionid"> + <data type="long"/> + </attribute> + </element> + <ref name="interface-options"/> + </interleave> + </group> + </choice> <optional> <attribute name="trustGuestRxFilters"> diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 92e4e0ee605f..ab736713271b 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1392,6 +1392,7 @@ libxlMakeNic(virDomainDef *def, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported interface type %s"), diff --git a/src/libxl/xen_common.c b/src/libxl/xen_common.c index d90ec674e5f6..10ac8013739f 100644 --- a/src/libxl/xen_common.c +++ b/src/libxl/xen_common.c @@ -1678,6 +1678,7 @@ xenFormatNet(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"), virDomainNetTypeToString(net->type)); return -1; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index c63f4b14eaf8..9328f242df6a 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -423,6 +423,7 @@ static int virLXCControllerGetNICIndexes(virLXCController *ctrl) case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type %s"), virDomainNetTypeToString(actualType)); diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 6bd2cdd205d4..8a7135ff4733 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3466,6 +3466,7 @@ lxcDomainAttachDeviceNetLive(virLXCDriver *driver, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Network device type is not supported")); goto cleanup; @@ -3522,6 +3523,7 @@ lxcDomainAttachDeviceNetLive(virLXCDriver *driver, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: default: /* no-op */ @@ -3965,6 +3967,7 @@ lxcDomainDetachDeviceNetLive(virDomainObj *vm, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only bridged veth devices can be detached")); goto cleanup; diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index fab23fa2b11f..6b12bff25cb8 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -597,6 +597,7 @@ virLXCProcessSetupInterfaces(virLXCDriver *driver, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, _("Unsupported network type %s"), @@ -1609,6 +1610,7 @@ virLXCProcessReconnectNotifyNets(virDomainDef *def) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 812176ab992e..1523ca704794 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3962,6 +3962,7 @@ qemuBuildHostNetProps(virDomainNetDef *net) case VIR_DOMAIN_NET_TYPE_HOSTDEV: /* Should have been handled earlier via PCI/USB hotplug code. */ case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -8182,6 +8183,7 @@ qemuBuildInterfaceConnect(virDomainObj *vm, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -8280,6 +8282,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: /* nada */ break; @@ -8319,6 +8322,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: /* These types don't use a network device on the host, but * instead use some other type of connection to the emulated diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9d5dd07958ad..45f00e162d63 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -9733,6 +9733,7 @@ qemuDomainNetSupportsMTU(virDomainNetType type) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 30f146f2f4d9..751fa84013b0 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1231,6 +1231,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("hotplug of interface type of %s is not implemented yet"), @@ -3387,6 +3388,7 @@ qemuDomainChangeNetFilter(virDomainObj *vm, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("filters not supported on interfaces of type %s"), virDomainNetTypeToString(virDomainNetGetActualType(newdev))); @@ -3739,6 +3741,7 @@ qemuDomainChangeNet(virQEMUDriver *driver, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("unable to change config on '%s' network type"), virDomainNetTypeToString(newdev->type)); diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c index fa34ecd5130f..3ec92fdd7d36 100644 --- a/src/qemu/qemu_interface.c +++ b/src/qemu/qemu_interface.c @@ -119,6 +119,7 @@ qemuInterfaceStartDevice(virDomainNetDef *net) case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: /* these types all require no action */ break; @@ -206,6 +207,7 @@ qemuInterfaceStopDevice(virDomainNetDef *net) case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: /* these types all require no action */ break; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cfcf879f5908..5c8413a6b64c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3262,6 +3262,7 @@ qemuProcessNotifyNets(virDomainDef *def) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -8267,6 +8268,7 @@ void qemuProcessStop(virQEMUDriver *driver, case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: /* No special cleanup procedure for these types. */ break; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 6e457f381412..41765bba3710 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1761,6 +1761,7 @@ qemuValidateNetSupportsCoalesce(virDomainNetType type) case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 7b705b895ed1..b7b997e83540 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -3973,6 +3973,7 @@ virVMXFormatEthernet(virDomainNetDef *def, int controller, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: + case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"), virDomainNetTypeToString(def->type)); return -1; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 451f51d633d8..d2ea4d1c7b44 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1070,6 +1070,7 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd) case VIR_DOMAIN_NET_TYPE_VDPA: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_LAST: vshError(ctl, _("No support for %s in command 'attach-interface'"), type); -- 2.37.2

On Wed, Aug 17, 2022 at 02:50:39PM +0200, Martin Kletzander wrote:
This represents an interface connected to a VMWare Distributed Switch, previously obscured as a dummy interface.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.rst | 30 +++++++++++---- src/ch/ch_monitor.c | 1 + src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 7 ++++ src/conf/netdev_bandwidth_conf.c | 1 + src/conf/schemas/domaincommon.rng | 23 +++++++++++ src/libxl/libxl_conf.c | 1 + src/libxl/xen_common.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_driver.c | 3 ++ src/lxc/lxc_process.c | 2 + src/qemu/qemu_command.c | 4 ++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_hotplug.c | 3 ++ src/qemu/qemu_interface.c | 2 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 1 + src/vmx/vmx.c | 1 + tools/virsh-domain.c | 1 + 19 files changed, 141 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index ed0d9c19593b..3a8aa96fdc0a 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -5244,22 +5244,36 @@ Dummy network interface ^^^^^^^^^^^^^^^^^^^^^^^
An unconnected network interface sounds pretty pointless, but can show up for -example with VMWare when libvirt does not have any more information to provide. -Two such scenarios are currently known: +example with VMWare without any specified network to be connected to. +:since:`Since 8.7.0`
-1) network interface exists, but is not connected to any existing network -2) the interface is connected to something known as VMWare Distributed Switch +:: + + ... + <devices> + <interface type='dummy'> + <mac address='52:54:00:22:c9:42'/> + </interface> + </devices> + ...
-The difference between these two is not (yet?) discoverable by libvirt, so at -least the information gathered from the hypervisor is provided in the -element. :since:`Since 8.7.0` +VMWare Distributed Switch +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Interface can be connected to VMWare Distributed Switch, but since libvirt +cannot provide information about that architecture, the information presented +here is only what can be gathered from the VM configuration. VMs with this +interface type can be created, so that editing of the XML works properly, +however libvirt cannot guarantee that any changes in these parameters will be +valid in the hypervisor. :since:`Since 8.7.0`
::
... <devices> - <interface type='dummy'> + <interface type='vds'> <mac address='52:54:00:22:c9:42'/> + <source switchid='12345678-1234-1234-1234-123456789abc' portid='6' portgroupid='pg-4321' connectionid='12345'/> </interface> </devices> ...
@@ -8899,6 +8905,8 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, g_autofree char *vhost_path = NULL; g_autofree char *tap = NULL; g_autofree char *vhost = NULL; + g_autofree char *switchid = NULL; + g_autofree char *connectionid = NULL; const char *prefix = xmlopt ? xmlopt->config.netPrefix : NULL;
if (!(def = virDomainNetDefNew(xmlopt))) @@ -8932,6 +8940,13 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, portid = virXMLPropString(source_node, "portid"); }
+ if (def->type == VIR_DOMAIN_NET_TYPE_VDS) { + switchid = virXMLPropString(source_node, "switchid"); + portid = virXMLPropString(source_node, "portid"); + portgroup = virXMLPropString(source_node, "portgroupid"); + connectionid = virXMLPropString(source_node, "connectionid"); + } + if (def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) internal = virXMLPropString(source_node, "name");
@@ -9313,6 +9328,36 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, } break;
+ case VIR_DOMAIN_NET_TYPE_VDS: + if (!switchid) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing source switchid for interface type '%s'"), + virDomainNetTypeToString(def->type)); + goto error; + } + + if (virUUIDParse(switchid, def->data.vds.switch_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse switchid '%s'"), switchid); + goto error; + }
Report if switch id is missing, which is good.
+ + if (virStrToLong_ll(portid, NULL, 0, &def->data.vds.port_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse portid '%s'"), portid); + goto error; + } + + if (virStrToLong_ll(connectionid, NULL, 0, &def->data.vds.connection_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse connectionid '%s'"), connectionid); + goto error; + }
AFAICT, this may well crash if port id or connedtion id are missing, since it ends up passing NULL to strtol which is not defined to allow NULL IIUC.
+ + def->data.vds.portgroup_id = g_steal_pointer(&portgroup);
Allows portgroup id to be missing
+ + break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY: @@ -9495,6 +9540,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_VDPA: break; case VIR_DOMAIN_NET_TYPE_LAST: @@ -23683,7 +23729,21 @@ virDomainNetDefFormat(virBuffer *buf, def->data.vdpa.devicepath); sourceLines++; } + break; + + case VIR_DOMAIN_NET_TYPE_VDS: { + char switchidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(def->data.vds.switch_id, switchidstr); + virBufferEscapeString(buf, "<source switchid='%s'", switchidstr); + virBufferAsprintf(buf, " portid='%lld'", def->data.vds.port_id); + virBufferEscapeString(buf, " portgroupid='%s'", def->data.vds.portgroup_id); + virBufferAsprintf(buf, " connectionid='%lld'", def->data.vds.connection_id);
Based on this logic switch id, port id and connection id are mandatory, but missing portgroup_id would be handled gracefully.
+ + sourceLines++; + break; + }
case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY:
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5d530f957b0d..7f6ea1d8887d 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -3440,6 +3440,29 @@ <ref name="interface-options"/> </group>
+ <group> + <attribute name="type"> + <value>vds</value> + </attribute> + <interleave> + <element name="source"> + <attribute name="switchid"> + <ref name="UUID"/> + </attribute> + <attribute name="portid"> + <data type="long"/> + </attribute> + <attribute name="portgroupid"> + <data type="string"/> + </attribute> + <attribute name="connectionid"> + <data type="long"/> + </attribute>
Indicates all attributes are mandatory even though the code gracefully handles port group ID being missing. Overall there's some error checking missing when parsing I believe, or this needs relaxing for port group ID.
+ </element> + <ref name="interface-options"/> + </interleave> + </group> + </choice> <optional> <attribute name="trustGuestRxFilters">
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Tue, Aug 30, 2022 at 12:48:49PM +0100, Daniel P. Berrangé wrote:
On Wed, Aug 17, 2022 at 02:50:39PM +0200, Martin Kletzander wrote:
This represents an interface connected to a VMWare Distributed Switch, previously obscured as a dummy interface.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- docs/formatdomain.rst | 30 +++++++++++---- src/ch/ch_monitor.c | 1 + src/conf/domain_conf.c | 64 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 7 ++++ src/conf/netdev_bandwidth_conf.c | 1 + src/conf/schemas/domaincommon.rng | 23 +++++++++++ src/libxl/libxl_conf.c | 1 + src/libxl/xen_common.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_driver.c | 3 ++ src/lxc/lxc_process.c | 2 + src/qemu/qemu_command.c | 4 ++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_hotplug.c | 3 ++ src/qemu/qemu_interface.c | 2 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 1 + src/vmx/vmx.c | 1 + tools/virsh-domain.c | 1 + 19 files changed, 141 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index ed0d9c19593b..3a8aa96fdc0a 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -5244,22 +5244,36 @@ Dummy network interface ^^^^^^^^^^^^^^^^^^^^^^^
An unconnected network interface sounds pretty pointless, but can show up for -example with VMWare when libvirt does not have any more information to provide. -Two such scenarios are currently known: +example with VMWare without any specified network to be connected to. +:since:`Since 8.7.0`
-1) network interface exists, but is not connected to any existing network -2) the interface is connected to something known as VMWare Distributed Switch +:: + + ... + <devices> + <interface type='dummy'> + <mac address='52:54:00:22:c9:42'/> + </interface> + </devices> + ...
-The difference between these two is not (yet?) discoverable by libvirt, so at -least the information gathered from the hypervisor is provided in the -element. :since:`Since 8.7.0` +VMWare Distributed Switch +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Interface can be connected to VMWare Distributed Switch, but since libvirt +cannot provide information about that architecture, the information presented +here is only what can be gathered from the VM configuration. VMs with this +interface type can be created, so that editing of the XML works properly, +however libvirt cannot guarantee that any changes in these parameters will be +valid in the hypervisor. :since:`Since 8.7.0`
::
... <devices> - <interface type='dummy'> + <interface type='vds'> <mac address='52:54:00:22:c9:42'/> + <source switchid='12345678-1234-1234-1234-123456789abc' portid='6' portgroupid='pg-4321' connectionid='12345'/> </interface> </devices> ...
@@ -8899,6 +8905,8 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, g_autofree char *vhost_path = NULL; g_autofree char *tap = NULL; g_autofree char *vhost = NULL; + g_autofree char *switchid = NULL; + g_autofree char *connectionid = NULL; const char *prefix = xmlopt ? xmlopt->config.netPrefix : NULL;
if (!(def = virDomainNetDefNew(xmlopt))) @@ -8932,6 +8940,13 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, portid = virXMLPropString(source_node, "portid"); }
+ if (def->type == VIR_DOMAIN_NET_TYPE_VDS) { + switchid = virXMLPropString(source_node, "switchid"); + portid = virXMLPropString(source_node, "portid"); + portgroup = virXMLPropString(source_node, "portgroupid"); + connectionid = virXMLPropString(source_node, "connectionid"); + } + if (def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) internal = virXMLPropString(source_node, "name");
@@ -9313,6 +9328,36 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, } break;
+ case VIR_DOMAIN_NET_TYPE_VDS: + if (!switchid) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing source switchid for interface type '%s'"), + virDomainNetTypeToString(def->type)); + goto error; + } + + if (virUUIDParse(switchid, def->data.vds.switch_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse switchid '%s'"), switchid); + goto error; + }
Report if switch id is missing, which is good.
+ + if (virStrToLong_ll(portid, NULL, 0, &def->data.vds.port_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse portid '%s'"), portid); + goto error; + } + + if (virStrToLong_ll(connectionid, NULL, 0, &def->data.vds.connection_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse connectionid '%s'"), connectionid); + goto error; + }
AFAICT, this may well crash if port id or connedtion id are missing, since it ends up passing NULL to strtol which is not defined to allow NULL IIUC.
+ + def->data.vds.portgroup_id = g_steal_pointer(&portgroup);
Allows portgroup id to be missing
+ + break; + case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY: @@ -9495,6 +9540,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_DUMMY: + case VIR_DOMAIN_NET_TYPE_VDS: case VIR_DOMAIN_NET_TYPE_VDPA: break; case VIR_DOMAIN_NET_TYPE_LAST: @@ -23683,7 +23729,21 @@ virDomainNetDefFormat(virBuffer *buf, def->data.vdpa.devicepath); sourceLines++; } + break; + + case VIR_DOMAIN_NET_TYPE_VDS: { + char switchidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(def->data.vds.switch_id, switchidstr); + virBufferEscapeString(buf, "<source switchid='%s'", switchidstr); + virBufferAsprintf(buf, " portid='%lld'", def->data.vds.port_id); + virBufferEscapeString(buf, " portgroupid='%s'", def->data.vds.portgroup_id); + virBufferAsprintf(buf, " connectionid='%lld'", def->data.vds.connection_id);
Based on this logic switch id, port id and connection id are mandatory, but missing portgroup_id would be handled gracefully.
+ + sourceLines++; + break; + }
case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_DUMMY:
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5d530f957b0d..7f6ea1d8887d 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -3440,6 +3440,29 @@ <ref name="interface-options"/> </group>
+ <group> + <attribute name="type"> + <value>vds</value> + </attribute> + <interleave> + <element name="source"> + <attribute name="switchid"> + <ref name="UUID"/> + </attribute> + <attribute name="portid"> + <data type="long"/> + </attribute> + <attribute name="portgroupid"> + <data type="string"/> + </attribute> + <attribute name="connectionid"> + <data type="long"/> + </attribute>
Indicates all attributes are mandatory even though the code gracefully handles port group ID being missing.
Overall there's some error checking missing when parsing I believe, or this needs relaxing for port group ID.
Definitely more checks, I sent them now so that we can make it before release. Thanks for finding this out.
+ </element> + <ref name="interface-options"/> + </interleave> + </group> + </choice> <optional> <attribute name="trustGuestRxFilters">
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Since we cannot properly plug a new VM into the distributed switch, we can at least report the provided pieces of information, so that XML editing still works even for VMs with such interfaces. https://bugzilla.redhat.com/show_bug.cgi?id=1988211 Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/vmx/vmx.c | 76 ++++++++++++++++++---- tests/vmx2xmldata/ethernet-vds.vmx | 11 ++++ tests/vmx2xmldata/ethernet-vds.xml | 24 +++++++ tests/vmx2xmltest.c | 1 + tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx | 18 +++++ tests/xml2vmxdata/xml2vmx-ethernet-vds.xml | 15 +++++ tests/xml2vmxtest.c | 1 + 7 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 tests/vmx2xmldata/ethernet-vds.vmx create mode 100644 tests/vmx2xmldata/ethernet-vds.xml create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.xml diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index b7b997e83540..9ad463658aa8 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -2700,6 +2700,13 @@ virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def) char networkName_name[48] = ""; char *networkName = NULL; + char switchId_name[48] = ""; + char *switchId = NULL; + + char portId_name[48] = ""; + char portgroupId_name[48] = ""; + char connectionId_name[48] = ""; + int netmodel = VIR_DOMAIN_NET_MODEL_UNKNOWN; if (def == NULL || *def != NULL) { @@ -2721,6 +2728,13 @@ virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def) VMX_BUILD_NAME(networkName); VMX_BUILD_NAME(vnet); + g_snprintf(prefix, sizeof(prefix), "ethernet%d.dvs", controller); + + VMX_BUILD_NAME(switchId); + VMX_BUILD_NAME(portId); + VMX_BUILD_NAME(portgroupId); + VMX_BUILD_NAME(connectionId); + /* vmx:present */ if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) return -1; @@ -2836,19 +2850,36 @@ virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def) goto cleanup; } + if (virVMXGetConfigString(conf, switchId_name, &switchId, true) < 0) + goto cleanup; + /* Setup virDomainNetDef */ - if (connectionType == NULL && networkName == NULL) { - /* - * Having neither a connectionType nor a network name can mean two - * things: - * - * 1) there is no connection of that nic - * 2) the nic is connected to VMWare Distributed Switch - * - * But we do not see any difference between these and hence we report - * the closest thing to at least make virt-v2v and others work when they - * read the domain XML. - */ + if (switchId) { + (*def)->type = VIR_DOMAIN_NET_TYPE_VDS; + + if (virUUIDParse(switchId, (*def)->data.vds.switch_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + switchId); + goto cleanup; + } + + if (virVMXGetConfigString(conf, + portgroupId_name, + &(*def)->data.vds.portgroup_id, + false) < 0 || + virVMXGetConfigLong(conf, + portId_name, + &(*def)->data.vds.port_id, + 0, + false) < 0 || + virVMXGetConfigLong(conf, + connectionId_name, + &(*def)->data.vds.connection_id, + 0, + false) < 0) + goto cleanup; + } else if (connectionType == NULL && networkName == NULL) { (*def)->type = VIR_DOMAIN_NET_TYPE_DUMMY; } else if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) { (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE; @@ -3962,6 +3993,26 @@ virVMXFormatEthernet(virDomainNetDef *def, int controller, case VIR_DOMAIN_NET_TYPE_DUMMY: break; + case VIR_DOMAIN_NET_TYPE_VDS: { + unsigned char *uuid = def->data.vds.switch_id; + + virBufferAsprintf(buffer, "ethernet%d.dvs.switchId = \"%02x %02x %02x %02x %02x " + "%02x %02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n", + controller, uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], + uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], + uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); + + virBufferAsprintf(buffer, "ethernet%d.dvs.portId = \"%lld\"\n", + controller, def->data.vds.port_id); + + virBufferAsprintf(buffer, "ethernet%d.dvs.", controller); + virBufferEscapeString(buffer, "portgroupId = \"%s\"\n", def->data.vds.portgroup_id); + + virBufferAsprintf(buffer, "ethernet%d.dvs.connectionId = \"%lld\"\n", + controller, def->data.vds.connection_id); + break; + } + case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_SERVER: @@ -3973,7 +4024,6 @@ virVMXFormatEthernet(virDomainNetDef *def, int controller, case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_VDPA: - case VIR_DOMAIN_NET_TYPE_VDS: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"), virDomainNetTypeToString(def->type)); return -1; diff --git a/tests/vmx2xmldata/ethernet-vds.vmx b/tests/vmx2xmldata/ethernet-vds.vmx new file mode 100644 index 000000000000..f68587bcf181 --- /dev/null +++ b/tests/vmx2xmldata/ethernet-vds.vmx @@ -0,0 +1,11 @@ +config.version = "8" +virtualHW.version = "4" +ethernet0.present = "true" +ethernet0.virtualDev = "e1000e" +ethernet0.addressType = "vpx" +ethernet0.generatedAddress = "00:50:56:87:65:43" +ethernet0.dvs.switchId = "50 34 26 b2 94 e9 3b 16-1d 68 87 bf ff 4a 54 40" +ethernet0.dvs.portId = "5" +ethernet0.dvs.portgroupId = "dvportgroup-1285" +ethernet0.dvs.connectionId = "408217997" +displayName = "test" diff --git a/tests/vmx2xmldata/ethernet-vds.xml b/tests/vmx2xmldata/ethernet-vds.xml new file mode 100644 index 000000000000..ab842b168c9b --- /dev/null +++ b/tests/vmx2xmldata/ethernet-vds.xml @@ -0,0 +1,24 @@ +<domain type='vmware'> + <name>test</name> + <uuid>00000000-0000-0000-0000-000000000000</uuid> + <memory unit='KiB'>32768</memory> + <currentMemory unit='KiB'>32768</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686'>hvm</type> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <interface type='vds'> + <mac address='00:50:56:87:65:43' type='generated'/> + <source switchid='503426b2-94e9-3b16-1d68-87bfff4a5440' portid='5' portgroupid='dvportgroup-1285' connectionid='408217997'/> + <model type='e1000e'/> + </interface> + <video> + <model type='vmvga' vram='4096' primary='yes'/> + </video> + </devices> +</domain> diff --git a/tests/vmx2xmltest.c b/tests/vmx2xmltest.c index 3ab39148e0a4..07d7bf24c2b3 100644 --- a/tests/vmx2xmltest.c +++ b/tests/vmx2xmltest.c @@ -237,6 +237,7 @@ mymain(void) DO_TEST("ethernet-vpx"); DO_TEST("ethernet-other"); DO_TEST("ethernet-dummy"); + DO_TEST("ethernet-vds"); DO_TEST("serial-file"); DO_TEST("serial-device"); diff --git a/tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx b/tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx new file mode 100644 index 000000000000..bcc04bc21a6e --- /dev/null +++ b/tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx @@ -0,0 +1,18 @@ +.encoding = "UTF-8" +config.version = "8" +virtualHW.version = "4" +guestOS = "other" +uuid.bios = "56 4d 9b ef ac d9 b4 e0-c8 f0 ae a8 b9 10 35 15" +displayName = "ethernet-vpx" +memsize = "4" +numvcpus = "1" +floppy0.present = "false" +floppy1.present = "false" +ethernet0.present = "true" +ethernet0.virtualDev = "e1000e" +ethernet0.dvs.switchId = "50 34 26 b2 94 e9 3b 16-1d 68 87 bf ff 4a 54 40" +ethernet0.dvs.portId = "5" +ethernet0.dvs.portgroupId = "dvportgroup-1285" +ethernet0.dvs.connectionId = "408217997" +ethernet0.addressType = "vpx" +ethernet0.generatedAddress = "00:50:56:87:65:43" diff --git a/tests/xml2vmxdata/xml2vmx-ethernet-vds.xml b/tests/xml2vmxdata/xml2vmx-ethernet-vds.xml new file mode 100644 index 000000000000..69d44a62da1c --- /dev/null +++ b/tests/xml2vmxdata/xml2vmx-ethernet-vds.xml @@ -0,0 +1,15 @@ +<domain type='vmware'> + <name>ethernet-vpx</name> + <uuid>564d9bef-acd9-b4e0-c8f0-aea8b9103515</uuid> + <memory unit='KiB'>4096</memory> + <os> + <type>hvm</type> + </os> + <devices> + <interface type='vds'> + <mac address='00:50:56:87:65:43' type='generated'/> + <source switchid='503426b2-94e9-3b16-1d68-87bfff4a5440' portid='5' portgroupid='dvportgroup-1285' connectionid='408217997'/> + <model type='e1000e'/> + </interface> + </devices> +</domain> diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 7723c1efabdd..c921c8a3b0eb 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -226,6 +226,7 @@ mymain(void) DO_TEST("ethernet-mac-type", "ethernet-mac-type", 4); DO_TEST("ethernet-dummy", "ethernet-dummy", 4); + DO_TEST("ethernet-vds", "ethernet-vds", 4); DO_TEST("serial-file", "serial-file", 4); DO_TEST("serial-device", "serial-device", 4); -- 2.37.2

On a Wednesday in 2022, Martin Kletzander wrote:
Previously (but still in this release) such interfaces were represented as dummy ones, but hopefully we can properly represent them still in the same release.
Martin Kletzander (5): tests: Fix vmx/xml filenames conf: Rewrite virNetDevVPortProfileCopy vmx: Require networkName for bridged and custom NICs conf, docs, schemas: Add support for interface type vds vmx: Add support for VDS interface
docs/formatdomain.rst | 30 ++++++-- src/ch/ch_monitor.c | 1 + src/conf/domain_conf.c | 73 ++++++++++++++++-- src/conf/domain_conf.h | 7 ++ src/conf/netdev_bandwidth_conf.c | 1 + src/conf/schemas/domaincommon.rng | 23 ++++++ src/libxl/libxl_conf.c | 1 + src/libxl/xen_common.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_driver.c | 3 + src/lxc/lxc_process.c | 2 + src/qemu/qemu_command.c | 4 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_hotplug.c | 3 + src/qemu/qemu_interface.c | 2 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 1 + src/util/virnetdevvportprofile.c | 18 +++-- src/util/virnetdevvportprofile.h | 5 +- src/vmx/vmx.c | 77 +++++++++++++++---- ...unmanaged-nodev.vmx => ethernet-dummy.vmx} | 0 ...unmanaged-nodev.xml => ethernet-dummy.xml} | 0 tests/vmx2xmldata/ethernet-vds.vmx | 11 +++ tests/vmx2xmldata/ethernet-vds.xml | 24 ++++++ tests/vmx2xmltest.c | 3 +- ...d-nodev.vmx => xml2vmx-ethernet-dummy.vmx} | 0 ...d-nodev.xml => xml2vmx-ethernet-dummy.xml} | 0 tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx | 18 +++++ tests/xml2vmxdata/xml2vmx-ethernet-vds.xml | 15 ++++ tests/xml2vmxtest.c | 3 +- tools/virsh-domain.c | 1 + 31 files changed, 292 insertions(+), 39 deletions(-) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.vmx => ethernet-dummy.vmx} (100%) rename tests/vmx2xmldata/{ethernet-unmanaged-nodev.xml => ethernet-dummy.xml} (100%) create mode 100644 tests/vmx2xmldata/ethernet-vds.vmx create mode 100644 tests/vmx2xmldata/ethernet-vds.xml rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.vmx => xml2vmx-ethernet-dummy.vmx} (100%) rename tests/xml2vmxdata/{xml2vmx-ethernet-unmanaged-nodev.xml => xml2vmx-ethernet-dummy.xml} (100%) create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.vmx create mode 100644 tests/xml2vmxdata/xml2vmx-ethernet-vds.xml
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (3)
-
Daniel P. Berrangé
-
Ján Tomko
-
Martin Kletzander