Adds a new interface type using UDP sockets, this seems only applicable to QEMU but have edited tree-wide to support the new interface type. The interface type required the addition of a "localaddr" (local address), this then maps into the following xml and qemu call. <interface type='udp'> <mac address='52:54:00:5c:67:56'/> <source address='127.0.0.1' port='11112' > <local address='127.0.0.1' port='22222'/> </source> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> ... QEMU call: -net socket,udp=127.0.0.1:11112,localaddr=127.0.0.1:22222 Notice the xml "local" entry becomes the "localaddr" for the qemu call. reference: http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg00629.html Signed-off-by: Jonathan Toppins <jtoppins@xxxxxxxxxxxxxxxxxxx> --- since v1: I expect there will be one more round, thanks for the comments thus far. Wanted to go a head and send this out since it has been a little to long to get to this point. Some final issues I am seeing: * there seems to be some trouble with adding a new UDP type interface to a running VM. Stanley who is CC'ed and helping me test has more details. * unittests pass even though qemuxml2argvtest still fails, this appears to be due to disk-drive-network-gluster failing - analysis looks to be the URI is incorrect, not enough slashes - cuz more is better ;) * please verify I have added the schema correctly, was kinda confusing Code Comments: [Laine Stump] * [DONE] change to using "local" as a nested element inside the "source" element * [DONE] enhance schema to validate the new formatting of the source and local elements [Ján Tomko] * [DONE] implement unit tests in tests/qemuxml2argvtest.c and tests/qemuxml2xmltest.c * [DONE] increase verbosity and note when the feature was added in formatdomain.html.in docs/formatdomain.html.in | 24 ++++++++ docs/schemas/domaincommon.rng | 27 +++++++++ src/conf/domain_conf.c | 74 ++++++++++++++++++++++-- src/conf/domain_conf.h | 3 + src/conf/netdev_bandwidth_conf.h | 1 + src/libxl/libxl_conf.c | 1 + src/lxc/lxc_controller.c | 1 + src/lxc/lxc_process.c | 1 + src/qemu/qemu_command.c | 12 ++++ src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_interface.c | 2 + src/uml/uml_conf.c | 5 ++ src/xenconfig/xen_sxpr.c | 1 + tests/qemuxml2argvdata/qemuxml2argv-net-udp.args | 6 ++ tests/qemuxml2argvdata/qemuxml2argv-net-udp.xml | 34 +++++++++++ tests/qemuxml2argvtest.c | 1 + tests/qemuxml2xmltest.c | 1 + tools/virsh-domain.c | 1 + 18 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-udp.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-udp.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 5ca8ede..d307d4d 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4260,6 +4260,30 @@ </devices> ...</pre> + <h5><a name="elementsNICSUDP">UDP unicast tunnel</a></h5> + + <p> + A UDP unicast architecture provides a virtual network which enables + connections between Qemu instances using Qemu's UDP infrastructure. + + The xml "source" address is the endpoint address to which the UDP socket + packets will be sent from the host running QEMU. + The xml "local" address is the address of the interface from which the + UDP socket packets will originate from the qemu host. + <span class="since">Since 1.2.19</span></p> + +<pre> + ... + <devices> + <interface type='udp'> + <mac address='52:54:00:22:c9:42'/> + <source address='127.0.0.1' port='11115'> + <local address='127.0.0.1' port='11116'/> + </source> + </interface> + </devices> + ...</pre> + <h5><a name="elementsNICSModel">Setting the NIC model</a></h5> <pre> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index ccc74cc..f196177 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2181,6 +2181,33 @@ </group> <group> <attribute name="type"> + <choice> + <value>udp</value> + </choice> + </attribute> + <interleave> + <element name="source"> + <attribute name="address"> + <ref name="ipv4Addr"/> + </attribute> + <attribute name="port"> + <ref name="PortNumber"/> + </attribute> + <element name="local"> + <attribute name="address"> + <ref name="ipv4Addr"/> + </attribute> + <attribute name="port"> + <ref name="PortNumber"/> + </attribute> + <empty/> + </element> + </element> + <ref name="interface-options"/> + </interleave> + </group> + <group> + <attribute name="type"> <value>server</value> </attribute> <interleave> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c5e9653..70e8b39 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -397,7 +397,8 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST, "bridge", "internal", "direct", - "hostdev") + "hostdev", + "udp") VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST, "default", @@ -1645,7 +1646,9 @@ void virDomainNetDefFree(virDomainNetDefPtr def) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: VIR_FREE(def->data.socket.address); + VIR_FREE(def->data.socket.localaddr); break; case VIR_DOMAIN_NET_TYPE_NETWORK: @@ -8589,6 +8592,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, char *script = NULL; char *address = NULL; char *port = NULL; + char *localaddr = NULL; + char *localport = NULL; char *model = NULL; char *backend = NULL; char *txmode = NULL; @@ -8701,10 +8706,18 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, } else if (!address && (def->type == VIR_DOMAIN_NET_TYPE_SERVER || def->type == VIR_DOMAIN_NET_TYPE_CLIENT || - def->type == VIR_DOMAIN_NET_TYPE_MCAST) && + def->type == VIR_DOMAIN_NET_TYPE_MCAST || + def->type == VIR_DOMAIN_NET_TYPE_UDP) && xmlStrEqual(cur->name, BAD_CAST "source")) { address = virXMLPropString(cur, "address"); port = virXMLPropString(cur, "port"); + if (!localaddr && def->type == VIR_DOMAIN_NET_TYPE_UDP) { + xmlNodePtr tmpnode = ctxt->node; + ctxt->node = cur; + localaddr = virXPathString("string(./local/@address)", ctxt); + localport = virXPathString("string(./local/@port)", ctxt); + ctxt->node = tmpnode; + } } else if (xmlStrEqual(cur->name, BAD_CAST "ip")) { virDomainNetIpDefPtr ip = NULL; @@ -8942,6 +8955,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: if (port == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No <source> 'port' attribute " @@ -8957,7 +8971,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, if (address == NULL) { if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT || - def->type == VIR_DOMAIN_NET_TYPE_MCAST) { + def->type == VIR_DOMAIN_NET_TYPE_MCAST || + def->type == VIR_DOMAIN_NET_TYPE_UDP) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No <source> 'address' attribute " "specified with socket interface")); @@ -8967,6 +8982,32 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, def->data.socket.address = address; address = NULL; } + + if (def->type != VIR_DOMAIN_NET_TYPE_UDP) + break; + + if (localport == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No <local> 'port' attribute " + "specified with socket interface")); + goto error; + } + if (virStrToLong_i(localport, NULL, 10, &def->data.socket.localport) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <local> 'port' attribute " + "with socket interface")); + goto error; + } + + if (localaddr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No <local> 'address' attribute " + "specified with socket interface")); + goto error; + } else { + def->data.socket.localaddr = localaddr; + localaddr = NULL; + } break; case VIR_DOMAIN_NET_TYPE_INTERNAL: @@ -19959,13 +20000,34 @@ virDomainNetDefFormat(virBufferPtr buf, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: if (def->data.socket.address) { - virBufferAsprintf(buf, "<source address='%s' port='%d'/>\n", - def->data.socket.address, def->data.socket.port); + virBufferAsprintf(buf, "<source address='%s' port='%d'", + def->data.socket.address, + def->data.socket.port); } else { - virBufferAsprintf(buf, "<source port='%d'/>\n", + virBufferAsprintf(buf, "<source port='%d'", def->data.socket.port); } + + if (def->type != VIR_DOMAIN_NET_TYPE_UDP) { + virBufferAddLit(buf, "/>\n"); + break; + } + + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + + if (def->data.socket.localaddr) { + virBufferAsprintf(buf, "<local address='%s' port='%d'/>\n", + def->data.socket.localaddr, + def->data.socket.localport); + } else { + virBufferAsprintf(buf, "<local port='%d'/>", + def->data.socket.localport); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</source>\n"); break; case VIR_DOMAIN_NET_TYPE_INTERNAL: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 961e4ed..f043554 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -923,6 +923,7 @@ typedef enum { VIR_DOMAIN_NET_TYPE_INTERNAL, VIR_DOMAIN_NET_TYPE_DIRECT, VIR_DOMAIN_NET_TYPE_HOSTDEV, + VIR_DOMAIN_NET_TYPE_UDP, VIR_DOMAIN_NET_TYPE_LAST } virDomainNetType; @@ -1025,6 +1026,8 @@ struct _virDomainNetDef { struct { char *address; int port; + char *localaddr; + int localport; } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */ struct { char *name; diff --git a/src/conf/netdev_bandwidth_conf.h b/src/conf/netdev_bandwidth_conf.h index 6cbf4ae..cdeac09 100644 --- a/src/conf/netdev_bandwidth_conf.h +++ b/src/conf/netdev_bandwidth_conf.h @@ -53,6 +53,7 @@ static inline bool virNetDevSupportBandwidth(virDomainNetType type) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_LAST: diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index e845759..a76ad5a 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1177,6 +1177,7 @@ libxlMakeNic(virDomainDefPtr def, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_HOSTDEV: diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index d36bc9b..0e6a3e1 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -385,6 +385,7 @@ static int virLXCControllerGetNICIndexes(virLXCControllerPtr ctrl) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_HOSTDEV: diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index ade0ed7..57e3880 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -566,6 +566,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_LAST: case VIR_DOMAIN_NET_TYPE_HOSTDEV: diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index abc57d7..1210fb2 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5594,6 +5594,17 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, type_sep = ','; break; + case VIR_DOMAIN_NET_TYPE_UDP: + virBufferAsprintf(&buf, "socket%cudp=%s:%d%clocaladdr=%s:%d", + type_sep, + net->data.socket.address, + net->data.socket.port, + type_sep, + net->data.socket.localaddr, + net->data.socket.localport); + type_sep = ','; + break; + case VIR_DOMAIN_NET_TYPE_USER: default: virBufferAddLit(&buf, "user"); @@ -8667,6 +8678,7 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_LAST: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e71a204..ac683ad 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2402,6 +2402,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: if (STRNEQ_NULLABLE(olddev->data.socket.address, newdev->data.socket.address) || olddev->data.socket.port != newdev->data.socket.port) { diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c index 01226ac..4d55e4d 100644 --- a/src/qemu/qemu_interface.c +++ b/src/qemu/qemu_interface.c @@ -100,6 +100,7 @@ qemuInterfaceStartDevice(virDomainNetDefPtr net) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_LAST: @@ -187,6 +188,7 @@ qemuInterfaceStopDevice(virDomainNetDefPtr net) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_LAST: diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 90deb2a..afc0375 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -195,6 +195,11 @@ umlBuildCommandLineNet(virConnectPtr conn, _("TCP client networking type not supported")); goto error; + case VIR_DOMAIN_NET_TYPE_UDP: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("UDP networking type not supported")); + goto error; + case VIR_DOMAIN_NET_TYPE_MCAST: /* ethNNN=tuntap,macaddr,ipaddr,port */ virBufferAddLit(&buf, "mcast"); diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c index 05e938a..1d43ec1 100644 --- a/src/xenconfig/xen_sxpr.c +++ b/src/xenconfig/xen_sxpr.c @@ -1962,6 +1962,7 @@ xenFormatSxprNet(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_HOSTDEV: diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-udp.args b/tests/qemuxml2argvdata/qemuxml2argv-net-udp.args new file mode 100644 index 0000000..f8d48a8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-udp.args @@ -0,0 +1,6 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ +/usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \ +-no-acpi -boot c -usb -hda /dev/HostVG/QEMUGuest1 -net nic,\ +macaddr=52:54:00:8c:b9:05,vlan=0,model=rtl8139 -net socket,udp=192.168.10.1:5555,localaddr=192.168.10.1:5556,\ +vlan=0 -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-udp.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-udp.xml new file mode 100644 index 0000000..c19107d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-udp.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <controller type='usb' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <interface type='udp'> + <mac address='52:54:00:8c:b9:05'/> + <source address='192.168.10.1' port='5555'> + <local address='192.168.10.1' port='5556'/> + </source> + <model type='rtl8139'/> + </interface> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c2482e6..d4432df 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1029,6 +1029,7 @@ mymain(void) DO_TEST("net-client", NONE); DO_TEST("net-server", NONE); DO_TEST("net-mcast", NONE); + DO_TEST("net-udp", NONE); DO_TEST("net-hostdev", QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("net-hostdev-multidomain", diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 5c1c2e9..d41954e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -628,6 +628,7 @@ mymain(void) DO_TEST("memory-hotplug"); DO_TEST("memory-hotplug-nonuma"); DO_TEST("memory-hotplug-dimm"); + DO_TEST("net-udp"); virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 8d2700f..b029b65 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1005,6 +1005,7 @@ cmdAttachInterface(vshControl *ctl, const vshCmd *cmd) case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_UDP: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_HOSTDEV: case VIR_DOMAIN_NET_TYPE_LAST: -- 2.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list