The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3008

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Closes #3002

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 0313f486461d0b90e928a4d6fe972ce1614fd42b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 3 Mar 2017 17:43:34 -0500
Subject: [PATCH] Add "vlan" property to "macvlan" interfaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #3002

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 doc/api-extensions.md |  8 ++++++++
 doc/configuration.md  |  1 +
 lxd/api_1.0.go        |  1 +
 lxd/container.go      |  2 ++
 lxd/container_lxc.go  | 34 ++++++++++++++++++++++++++++++----
 lxd/networks_utils.go | 42 +++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 4a2e182..22c7f4a 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -217,3 +217,11 @@ Introduces the ability to rename a volume group by setting 
"storage.lvm.vg\_name
 
 ## storage\_lvm\_thinpool\_rename
 Introduces the ability to rename a thinpool name by setting 
"storage.thinpool\_name".
+
+## network\_vlan
+This adds a new "vlan" property to "macvlan" network devices.
+
+When set, this will instruct LXD to attach to the specified VLAN. LXD
+will look for an existing interface for that VLAN on the host. If one
+can't be found it will create one itself and then use that as the
+macvlan parent.
diff --git a/doc/configuration.md b/doc/configuration.md
index 3a6efec..aa8f07c 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -213,6 +213,7 @@ host\_name              | string    | randomly assigned | 
no        | bridged, p
 hwaddr                  | string    | randomly assigned | no        | all      
                     | -             | The MAC address of the new interface
 mtu                     | integer   | parent MTU        | no        | all      
                     | -             | The MTU of the new interface
 parent                  | string    | -                 | yes       | 
physical, bridged, macvlan    | -             | The name of the host device or 
bridge
+vlan                    | integer   | -                 | no        | macvlan  
                     | network\_vlan | The VLAN ID to attach to
 ipv4.address            | string    | -                 | no        | bridged  
                     | network       | An IPv4 address to assign to the 
container through DHCP
 ipv6.address            | string    | -                 | no        | bridged  
                     | network       | An IPv6 address to assign to the 
container through DHCP
 security.mac\_filtering | boolean   | false             | no        | bridged  
                     | network       | Prevent the container from spoofing 
another's MAC address
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index d7bd673..9dfe7b5 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -95,6 +95,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
                        "network_dhcp_expiry",
                        "storage_lvm_vg_rename",
                        "storage_lvm_thinpool_rename",
+                       "network_vlan",
                },
                APIStatus:  "stable",
                APIVersion: version.APIVersion,
diff --git a/lxd/container.go b/lxd/container.go
index 06939e5..1c5f8cd 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -107,6 +107,8 @@ func containerValidDeviceConfigKey(t, k string) bool {
                        return true
                case "parent":
                        return true
+               case "vlan":
+                       return true
                case "ipv4.address":
                        return true
                case "ipv6.address":
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index c122ecd..acb5217 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1224,11 +1224,16 @@ func (c *containerLXC) initLXC() error {
                                return err
                        }
 
-                       if shared.StringInSlice(m["nictype"], 
[]string{"bridged", "physical", "macvlan"}) {
+                       if shared.StringInSlice(m["nictype"], 
[]string{"bridged", "physical"}) {
                                err = lxcSetConfigItem(cc, "lxc.network.link", 
m["parent"])
                                if err != nil {
                                        return err
                                }
+                       } else if m["nictype"] == "macvlan" {
+                               err = lxcSetConfigItem(cc, "lxc.network.link", 
networkGetHostDevice(m["parent"], m["vlan"]))
+                               if err != nil {
+                                       return err
+                               }
                        }
 
                        // Host Virtual NIC name
@@ -1489,8 +1494,7 @@ func (c *containerLXC) startCommon() (string, error) {
        }
 
        // Sanity checks for devices
-       for _, name := range c.expandedDevices.DeviceNames() {
-               m := c.expandedDevices[name]
+       for name, m := range c.expandedDevices {
                switch m["type"] {
                case "disk":
                        // When we want to attach a storage volume created via
@@ -1744,6 +1748,17 @@ func (c *containerLXC) startCommon() (string, error) {
                                        return "", err
                                }
                        }
+
+                       // Create VLAN devices
+                       if m["nictype"] == "macvlan" && m["vlan"] != "" {
+                               device := networkGetHostDevice(m["parent"], 
m["vlan"])
+                               if 
!shared.PathExists(fmt.Sprintf("/sys/class/net/%s", device)) {
+                                       err := shared.RunCommand("ip", "link", 
"add", "link", m["parent"], "name", device, "up", "type", "vlan", "id", 
m["vlan"])
+                                       if err != nil {
+                                               return "", err
+                                       }
+                               }
+                       }
                }
        }
 
@@ -5539,8 +5554,19 @@ func (c *containerLXC) createNetworkDevice(name string, 
m types.Device) (string,
 
        // Handle macvlan
        if m["nictype"] == "macvlan" {
+               // Deal with VLAN
+               device := m["parent"]
+               if m["vlan"] != "" {
+                       device = networkGetHostDevice(m["parent"], m["vlan"])
+                       if !shared.PathExists(fmt.Sprintf("/sys/class/net/%s", 
device)) {
+                               err := shared.RunCommand("ip", "link", "add", 
"link", m["parent"], "name", device, "up", "type", "vlan", "id", m["vlan"])
+                               if err != nil {
+                                       return "", err
+                               }
+                       }
+               }
 
-               err := exec.Command("ip", "link", "add", n1, "link", 
m["parent"], "type", "macvlan", "mode", "bridge").Run()
+               err := exec.Command("ip", "link", "add", n1, "link", device, 
"type", "macvlan", "mode", "bridge").Run()
                if err != nil {
                        return "", fmt.Errorf("Failed to create the new macvlan 
interface: %s", err)
                }
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 3418054..70e4334 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -105,7 +105,7 @@ func networkIsInUse(c container, name string) bool {
                        continue
                }
 
-               if d["parent"] == name {
+               if networkGetHostDevice(d["parent"], d["vlan"]) == name {
                        return true
                }
        }
@@ -113,6 +113,46 @@ func networkIsInUse(c container, name string) bool {
        return false
 }
 
+func networkGetHostDevice(parent string, vlan string) string {
+       // If no VLAN, just use the raw device
+       if vlan == "" {
+               return parent
+       }
+
+       // If no VLANs are configured, use the default pattern
+       defaultVlan := fmt.Sprintf("%s.%s", parent, vlan)
+       if !shared.PathExists("/proc/net/vlan/config") {
+               return defaultVlan
+       }
+
+       // Look for an existing VLAN
+       f, err := os.Open("/proc/net/vlan/config")
+       if err != nil {
+               return defaultVlan
+       }
+       defer f.Close()
+
+       scanner := bufio.NewScanner(f)
+       for scanner.Scan() {
+               // Only grab the lines we're interested in
+               s := strings.Split(scanner.Text(), "|")
+               if len(s) != 3 {
+                       continue
+               }
+
+               vlanIface := strings.TrimSpace(s[0])
+               vlanId := strings.TrimSpace(s[1])
+               vlanParent := strings.TrimSpace(s[2])
+
+               if vlanParent == parent && vlanId == vlan {
+                       return vlanIface
+               }
+       }
+
+       // Return the default pattern
+       return defaultVlan
+}
+
 func networkGetIP(subnet *net.IPNet, host int64) net.IP {
        // Convert IP to a big int
        bigIP := big.NewInt(0)
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to