[libvirt] [PATCH libvirt 9/9] qemu: implement user mode port <forward>

Marc-André Lureau marcandre.lureau at gmail.com
Tue May 15 17:13:42 UTC 2012


Implement port forwarding for user mode networking with QEMU.
---
 src/libvirt_private.syms                          |    3 +
 src/qemu/qemu_command.c                           |  139 +++++++++++++++++++++
 tests/qemuargv2xmltest.c                          |    3 +-
 tests/qemuxml2argvdata/qemuxml2argv-net-user.args |    5 +-
 4 files changed, 146 insertions(+), 4 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7d09f33..d497bce 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -396,6 +396,9 @@ virDomainNetInsert;
 virDomainNetRemove;
 virDomainNetRemoveByMac;
 virDomainNetTypeToString;
+virDomainNetForwardDefFree;
+virDomainNetForwardProtocolTypeFromString;
+virDomainNetForwardProtocolTypeToString;
 virDomainNostateReasonTypeFromString;
 virDomainNostateReasonTypeToString;
 virDomainNumatuneMemModeTypeFromString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 842b0fd..4cccc91 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2846,6 +2846,34 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
             virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf);
     }
 
+    if (netType == VIR_DOMAIN_NET_TYPE_USER) {
+        int i;
+
+        for (i = 0; i < net->data.user.nforward; ++i) {
+            char *host_addr = NULL;
+            char *guest_addr = NULL;
+            virDomainNetForwardDefPtr fwd = net->data.user.forwards[i];
+            const char *type = virDomainNetForwardProtocolTypeToString(fwd->type);
+            if (!type) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                "%s", _("Invalid forward type"));
+                return NULL;
+            }
+
+            if (fwd->has_host_addr)
+                host_addr = virSocketAddrFormat(&fwd->host_addr);
+            if (fwd->has_guest_addr)
+                guest_addr = virSocketAddrFormat(&fwd->guest_addr);
+
+            virBufferAsprintf(&buf, ",hostfwd=%s:%s:%d-%s:%d", type,
+                              host_addr ? host_addr : "", fwd->host_port,
+                              guest_addr ? guest_addr : "", fwd->guest_port);
+
+            VIR_FREE(host_addr);
+            VIR_FREE(guest_addr);
+        }
+    }
+
     if (virBufferError(&buf)) {
         virBufferFreeAndReset(&buf);
         virReportOOMError();
@@ -6713,6 +6741,94 @@ qemuFindNICForVLAN(int nnics,
 }
 
 
+static virDomainNetForwardDefPtr
+qemuParseNetForward(char *val)
+{
+    char *type, *host, *guest, *port;
+    virDomainNetForwardDefPtr def;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    type = val;
+    host = strchr(type, ':');
+    if (!host) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot parse hostfwd host '%s'"), val);
+        goto error;
+    }
+    *host = '\0';
+    host++;
+    guest = strchr(host, '-');
+    if (!guest) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot parse hostfwd guest '%s'"), val);
+        goto error;
+    }
+    *guest = '\0';
+    guest++;
+
+    if (STREQ(type, "")) {
+        def->type = VIR_DOMAIN_NET_FORWARD_PROTOCOL_TCP;
+    } else if ((def->type = virDomainNetForwardProtocolTypeFromString(type)) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown forward type '%s'"), type);
+        goto error;
+    }
+
+    port = strchr(host, ':');
+    if (!port) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Missing host port"));
+        goto error;
+    }
+    *port = '\0';
+    port++;
+    if (!STREQ(host, "")) {
+        if (virSocketAddrParse(&def->host_addr, host, AF_INET) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Bad host address '%s' for redirection"), host);
+            goto error;
+        }
+        def->has_host_addr = true;
+    }
+    if (virStrToLong_i(port, NULL, 10, &def->host_port) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Cannot parse host port"));
+        goto error;
+    }
+
+    port = strchr(guest, ':');
+    if (!port) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Missing guest port"));
+        goto error;
+    }
+    *port = '\0';
+    port++;
+    if (!STREQ(guest, "")) {
+        if (virSocketAddrParse(&def->guest_addr, guest, AF_INET) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Bad guest address '%s' for redirection"), guest);
+            goto error;
+        }
+        def->has_guest_addr = true;
+    }
+    if (virStrToLong_i(port, NULL, 10, &def->guest_port) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Cannot parse guest port"));
+        goto error;
+    }
+
+    return def;
+
+error:
+    virDomainNetForwardDefFree(def);
+    return NULL;
+}
+
 /*
  * Tries to parse a QEMU -net backend argument. Gets given
  * a list of all known -net frontend arguments to try and
@@ -6732,6 +6848,7 @@ qemuParseCommandLineNet(virCapsPtr caps,
     int wantvlan = 0;
     const char *tmp;
     int genmac = 1;
+    int nforward = 0;
     int i;
 
     tmp = strchr(val, ',');
@@ -6778,9 +6895,31 @@ qemuParseCommandLineNet(virCapsPtr caps,
                    STREQ(keywords[i], "ifname")) {
             def->ifname = values[i];
             values[i] = NULL;
+        } else if (def->type == VIR_DOMAIN_NET_TYPE_USER &&
+                   STREQ(keywords[i], "hostfwd")) {
+            nforward++;
         }
     }
 
+    if (nforward > 0) {
+        if (VIR_ALLOC_N(def->data.user.forwards, nforward) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        for (i = 0 ; i < nkeywords ; i++) {
+            virDomainNetForwardDefPtr fwd;
+            if (def->type != VIR_DOMAIN_NET_TYPE_USER ||
+                !STREQ(keywords[i], "hostfwd"))
+                continue;
+
+            if ((fwd = qemuParseNetForward(values[i])) == NULL)
+                goto cleanup;
+
+            def->data.user.forwards[def->data.user.nforward] = fwd;
+            def->data.user.nforward++;
+        }
+    }
 
     /* Done parsing the nic backend. Now to try and find corresponding
      * frontend, based off vlan number. NB this assumes a 1-1 mapping
diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c
index cf2862b..439218e 100644
--- a/tests/qemuargv2xmltest.c
+++ b/tests/qemuargv2xmltest.c
@@ -207,8 +207,7 @@ mymain(void)
     DO_TEST("misc-acpi");
     DO_TEST("misc-no-reboot");
     DO_TEST("misc-uuid");
-    /* Fixed in following commit */
-    /* DO_TEST("net-user"); */
+    DO_TEST("net-user");
     DO_TEST("net-virtio");
     DO_TEST("net-eth");
     DO_TEST("net-eth-ifname");
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
index 093ff01..db31e95 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
@@ -1,5 +1,6 @@
 LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
 pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net nic,\
-macaddr=00:11:22:33:44:55,vlan=0 -net user,vlan=0 -serial none -parallel none \
--usb
+macaddr=00:11:22:33:44:55,vlan=0 \
+-net user,vlan=0,hostfwd=tcp::2222-:22,hostfwd=udp:127.0.0.1:2242-10.0.2.15:42 \
+-serial none -parallel none -usb
-- 
1.7.10.1




More information about the libvir-list mailing list