From a09bbc024dc32700afb308b97c5d39efd4493517 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdonnat@suse.com>
Date: Wed, 5 Feb 2014 15:10:15 +0100
Subject: [PATCH] LXC from native: map vlan network type

The problem with VLAN is that the user still has to manually create the
vlan interface on the host. Then the generated configuration will use
it as a nerwork hostdev device. So the generated configurations of the
following two fragments are equivalent (see rhbz#1059637).

lxc.network.type = phys
lxc.network.link = eth0.5

lxc.network.type = vlan
lxc.network.link = eth0
lxc.network.vlan.id = 5
---
 src/lxc/lxc_native.c                          | 38 +++++++++++++++----
 .../lxcconf2xml-vlannetwork.config            | 12 ++++++
 .../lxcconf2xml-vlannetwork.xml               | 26 +++++++++++++
 tests/lxcconf2xmltest.c                       |  1 +
 4 files changed, 70 insertions(+), 7 deletions(-)
 create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config
 create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml

diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c
index 951e9ead1c..f9931767e5 100644
--- a/src/lxc/lxc_native.c
+++ b/src/lxc/lxc_native.c
@@ -414,22 +414,39 @@ lxcAddNetworkDefinition(virDomainDefPtr def,
                         const char *link,
                         const char *mac,
                         const char *flag,
-                        const char *macvlanmode)
+                        const char *macvlanmode,
+                        const char *vlanid)
 {
     virDomainNetDefPtr net = NULL;
     virDomainHostdevDefPtr hostdev = NULL;
+    bool isPhys, isVlan = false;
 
     if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "") ||
             STREQ(type, "none"))
         return 0;
 
-    if (type != NULL && STREQ(type, "phys")) {
-        if (!link ||
-            !(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES,
+    isPhys = STREQ(type, "phys");
+    isVlan = STREQ(type, "vlan");
+    if (type != NULL && (isPhys || isVlan)) {
+        if (!link) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Missing 'link' attribute for NIC"));
+            goto error;
+        }
+        if (!(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES,
                                             VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET,
                                             link)))
             goto error;
 
+        /* This still requires the user to manually setup the vlan interface
+         * on the host */
+        if (isVlan && vlanid) {
+            VIR_FREE(hostdev->source.caps.u.net.iface);
+            if (virAsprintf(&hostdev->source.caps.u.net.iface,
+                            "%s.%s", link, vlanid) < 0)
+                goto error;
+        }
+
         if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0)
             goto error;
         def->hostdevs[def->nhostdevs - 1] = hostdev;
@@ -457,6 +474,7 @@ typedef struct {
     char *mac;
     char *flag;
     char *macvlanmode;
+    char *vlanid;
     bool privnet;
     size_t networks;
 } lxcNetworkParseData;
@@ -472,7 +490,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
         status = lxcAddNetworkDefinition(parseData->def, parseData->type,
                                          parseData->link, parseData->mac,
                                          parseData->flag,
-                                         parseData->macvlanmode);
+                                         parseData->macvlanmode,
+                                         parseData->vlanid);
 
         if (status < 0)
             return -1;
@@ -487,6 +506,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
         parseData->mac = NULL;
         parseData->flag = NULL;
         parseData->macvlanmode = NULL;
+        parseData->vlanid = NULL;
 
         /* Keep the new value */
         parseData->type = value->str;
@@ -499,6 +519,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
         parseData->flag = value->str;
     else if (STREQ(name, "lxc.network.macvlan.mode"))
         parseData->macvlanmode = value->str;
+    else if (STREQ(name, "lxc.network.vlan.id"))
+        parseData->vlanid = value->str;
     else if (STRPREFIX(name, "lxc.network"))
         VIR_WARN("Unhandled network property: %s = %s",
                  name,
@@ -511,14 +533,16 @@ static int
 lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties)
 {
     int status;
-    lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, NULL, true, 0};
+    lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL,
+                                NULL, NULL, true, 0};
 
     virConfWalk(properties, lxcNetworkWalkCallback, &data);
 
     /* Add the last network definition found */
     status = lxcAddNetworkDefinition(def, data.type, data.link,
                                      data.mac, data.flag,
-                                     data.macvlanmode);
+                                     data.macvlanmode,
+                                     data.vlanid);
     if (status < 0)
         return -1;
     else if (status > 0)
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config
new file mode 100644
index 0000000000..327202c8af
--- /dev/null
+++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config
@@ -0,0 +1,12 @@
+# Template used to create this container: opensuse
+# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef
+
+lxc.network.type = vlan
+lxc.network.flags = up
+lxc.network.link = eth0
+lxc.network.hwaddr = 02:00:15:8f:05:c1
+lxc.network.vlan.id = 2
+
+lxc.rootfs = /var/lib/lxc/migrate_test/rootfs
+lxc.utsname = migrate_test
+lxc.autodev=1
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml
new file mode 100644
index 0000000000..7d6d51b5c3
--- /dev/null
+++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml
@@ -0,0 +1,26 @@
+<domain type='lxc'>
+  <name>migrate_test</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>65536</memory>
+  <currentMemory unit='KiB'>0</currentMemory>
+  <vcpu placement='static' current='0'>1</vcpu>
+  <os>
+    <type>exe</type>
+    <init>/sbin/init</init>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <filesystem type='mount' accessmode='passthrough'>
+      <source dir='/var/lib/lxc/migrate_test/rootfs'/>
+      <target dir='/'/>
+    </filesystem>
+    <hostdev mode='capabilities' type='net'>
+      <source>
+        <interface>eth0.2</interface>
+      </source>
+    </hostdev>
+  </devices>
+</domain>
diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c
index 77baf20831..e799893c0a 100644
--- a/tests/lxcconf2xmltest.c
+++ b/tests/lxcconf2xmltest.c
@@ -108,6 +108,7 @@ mymain(void)
     DO_TEST("nonenetwork", false);
     DO_TEST("physnetwork", false);
     DO_TEST("macvlannetwork", false);
+    DO_TEST("vlannetwork", false);
     DO_TEST("idmap", false);
     DO_TEST("memtune", false);
     DO_TEST("cputune", false);
-- 
GitLab