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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement port forwarding for user mode networking with QEMU.
---
 src/libvirt_private.syms                          |    3 +
 src/qemu/qemu_command.c                           |  154 ++++++++++++++++++++-
 tests/qemuargv2xmltest.c                          |    3 +-
 tests/qemuxml2argvdata/qemuxml2argv-net-user.args |    5 +-
 4 files changed, 158 insertions(+), 7 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 9f99dce..abd6f6a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2844,7 +2844,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                         _("scripts are not supported on interfaces of type %s"),
                         virDomainNetTypeToString(netType));
-        return NULL;
+        goto error;
     }
 
     switch (netType) {
@@ -2917,13 +2917,50 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
             virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf);
     }
 
+    if (net->nforward > 0) {
+        int i;
+
+        if (netType != VIR_DOMAIN_NET_TYPE_USER) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("forward is not supported on interfaces of type %s"),
+                            virDomainNetTypeToString(netType));
+            goto error;
+        }
+
+        for (i = 0; i < net->nforward; ++i) {
+            char *hostaddr = NULL;
+            char *guestaddr = NULL;
+            virDomainNetForwardDefPtr fwd = net->forwards[i];
+            const char *protocol = virDomainNetForwardProtocolTypeToString(fwd->protocol);
+            if (!protocol) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                "%s", _("Invalid forward protocol"));
+                goto error;
+            }
+
+            if (fwd->has_hostaddr)
+                hostaddr = virSocketAddrFormat(&fwd->hostaddr);
+            if (fwd->has_guestaddr)
+                guestaddr = virSocketAddrFormat(&fwd->guestaddr);
+
+            virBufferAsprintf(&buf, ",hostfwd=%s:%s:%d-%s:%d", protocol,
+                              hostaddr ? hostaddr : "", fwd->hostport,
+                              guestaddr ? guestaddr : "", fwd->guestport);
+
+            VIR_FREE(hostaddr);
+            VIR_FREE(guestaddr);
+        }
+    }
+
     if (virBufferError(&buf)) {
-        virBufferFreeAndReset(&buf);
         virReportOOMError();
-        return NULL;
     }
 
     return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
 }
 
 
@@ -6785,6 +6822,94 @@ qemuFindNICForVLAN(int nnics,
 }
 
 
+static virDomainNetForwardDefPtr
+qemuParseNetForward(char *val)
+{
+    char *protocol, *host, *guest, *port;
+    virDomainNetForwardDefPtr def;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    protocol = val;
+    host = strchr(protocol, ':');
+    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(protocol, "")) {
+        def->protocol = VIR_DOMAIN_NET_FORWARD_PROTOCOL_TCP;
+    } else if ((def->protocol = virDomainNetForwardProtocolTypeFromString(protocol)) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown forward protocol '%s'"), protocol);
+        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->hostaddr, host, AF_INET) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Bad host address '%s' for redirection"), host);
+            goto error;
+        }
+        def->has_hostaddr = true;
+    }
+    if (virStrToLong_i(port, NULL, 10, &def->hostport) < 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->guestaddr, guest, AF_INET) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Bad guest address '%s' for redirection"), guest);
+            goto error;
+        }
+        def->has_guestaddr = true;
+    }
+    if (virStrToLong_i(port, NULL, 10, &def->guestport) < 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
@@ -6804,6 +6929,7 @@ qemuParseCommandLineNet(virCapsPtr caps,
     int wantvlan = 0;
     const char *tmp;
     int genmac = 1;
+    int nforward = 0;
     int i;
 
     tmp = strchr(val, ',');
@@ -6850,9 +6976,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->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->forwards[def->nforward] = fwd;
+            def->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

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]
  Powered by Linux