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

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) ===

From 2e4484146b2d6ad039439f4e648dc50fe6c3079b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jan 2020 18:15:05 +0000
Subject: [PATCH 1/4] lxd/device: Relaxes requirement for name property when
 not using containers

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/infiniband_physical.go | 2 +-
 lxd/device/infiniband_sriov.go    | 2 +-
 lxd/device/nic_bridged.go         | 2 +-
 lxd/device/nic_ipvlan.go          | 2 +-
 lxd/device/nic_macvlan.go         | 3 ++-
 lxd/device/nic_p2p.go             | 2 +-
 lxd/device/nic_physical.go        | 2 +-
 lxd/device/nic_routed.go          | 2 +-
 lxd/device/nic_sriov.go           | 2 +-
 9 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/lxd/device/infiniband_physical.go 
b/lxd/device/infiniband_physical.go
index f1ba582621..6c6947b5bc 100644
--- a/lxd/device/infiniband_physical.go
+++ b/lxd/device/infiniband_physical.go
@@ -45,7 +45,7 @@ func (d *infinibandPhysical) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *infinibandPhysical) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/infiniband_sriov.go b/lxd/device/infiniband_sriov.go
index ea37fda93c..cb673e5ee5 100644
--- a/lxd/device/infiniband_sriov.go
+++ b/lxd/device/infiniband_sriov.go
@@ -46,7 +46,7 @@ func (d *infinibandSRIOV) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *infinibandSRIOV) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 6359052328..dd1e534799 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -83,7 +83,7 @@ func (d *nicBridged) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicBridged) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_ipvlan.go b/lxd/device/nic_ipvlan.go
index 480b8af1df..ee61a8353e 100644
--- a/lxd/device/nic_ipvlan.go
+++ b/lxd/device/nic_ipvlan.go
@@ -58,7 +58,7 @@ func (d *nicIPVLAN) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicIPVLAN) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index 5471bc869b..45df01b8d2 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -5,6 +5,7 @@ import (
 
        deviceConfig "github.com/lxc/lxd/lxd/device/config"
        "github.com/lxc/lxd/lxd/instance/instancetype"
+       "github.com/lxc/lxd/lxd/revert"
        "github.com/lxc/lxd/shared"
 )
 
@@ -30,7 +31,7 @@ func (d *nicMACVLAN) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicMACVLAN) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_p2p.go b/lxd/device/nic_p2p.go
index 038cb420a2..0bfa97462f 100644
--- a/lxd/device/nic_p2p.go
+++ b/lxd/device/nic_p2p.go
@@ -40,7 +40,7 @@ func (d *nicP2P) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicP2P) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index 09f4002568..54d98c6a0d 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -38,7 +38,7 @@ func (d *nicPhysical) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicPhysical) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_routed.go b/lxd/device/nic_routed.go
index 8b9db5eb31..3f6d0cb66f 100644
--- a/lxd/device/nic_routed.go
+++ b/lxd/device/nic_routed.go
@@ -63,7 +63,7 @@ func (d *nicRouted) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicRouted) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 
diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 7c426e01e5..b9fb4a8f30 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -49,7 +49,7 @@ func (d *nicSRIOV) validateConfig() error {
 
 // validateEnvironment checks the runtime environment for correctness.
 func (d *nicSRIOV) validateEnvironment() error {
-       if d.config["name"] == "" {
+       if d.inst.Type() == instancetype.Container && d.config["name"] == "" {
                return fmt.Errorf("Requires name property to start")
        }
 

From 254921475b1d9837cb1ea20e756131df1c2285b7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jan 2020 18:15:58 +0000
Subject: [PATCH 2/4] lxd/device/nic/macvlan: Clean up valid fields

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/nic_macvlan.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index 45df01b8d2..e1a9780748 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -20,7 +20,15 @@ func (d *nicMACVLAN) validateConfig() error {
        }
 
        requiredFields := []string{"parent"}
-       optionalFields := []string{"name", "mtu", "hwaddr", "vlan", 
"maas.subnet.ipv4", "maas.subnet.ipv6", "boot.priority"}
+       optionalFields := []string{
+               "name",
+               "mtu",
+               "hwaddr",
+               "vlan",
+               "maas.subnet.ipv4",
+               "maas.subnet.ipv6",
+               "boot.priority",
+       }
        err := d.config.Validate(nicValidationRules(requiredFields, 
optionalFields))
        if err != nil {
                return err

From 860005ce080d1bf0167d36a7f462242103d32fa3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jan 2020 18:17:55 +0000
Subject: [PATCH 3/4] lxd/device/nic/macvlan: Adds VM support and improves
 revert

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/nic_macvlan.go | 52 +++++++++++++++++++++++++++++----------
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index e1a9780748..43cb93a651 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -15,7 +15,7 @@ type nicMACVLAN struct {
 
 // validateConfig checks the supplied config for correctness.
 func (d *nicMACVLAN) validateConfig() error {
-       if d.inst.Type() != instancetype.Container {
+       if d.inst.Type() != instancetype.Container && d.inst.Type() != 
instancetype.VM {
                return ErrUnsupportedDevType
        }
 
@@ -61,6 +61,9 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, error) 
{
        networkCreateSharedDeviceLock.Lock()
        defer networkCreateSharedDeviceLock.Unlock()
 
+       revert := revert.New()
+       defer revert.Fail()
+
        saveData := make(map[string]string)
 
        // Decide which parent we should use based on VLAN setting.
@@ -78,20 +81,32 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, 
error) {
        // Record whether we created the parent device or not so it can be 
removed on stop.
        saveData["last_state.created"] = fmt.Sprintf("%t", statusDev != 
"existing")
 
-       // Create MACVLAN interface.
-       _, err = shared.RunCommand("ip", "link", "add", "dev", 
saveData["host_name"], "link", parentName, "type", "macvlan", "mode", "bridge")
-       if err != nil {
-               return nil, err
+       if shared.IsTrue(saveData["last_state.created"]) {
+               revert.Add(func() {
+                       NetworkRemoveInterfaceIfNeeded(d.state, parentName, 
d.inst, d.config["parent"], d.config["vlan"])
+               })
+       }
+
+       if d.inst.Type() == instancetype.Container {
+               // Create MACVLAN interface.
+               _, err = shared.RunCommand("ip", "link", "add", "dev", 
saveData["host_name"], "link", parentName, "type", "macvlan", "mode", "bridge")
+               if err != nil {
+                       return nil, err
+               }
+       } else if d.inst.Type() == instancetype.VM {
+               // Create MACVTAP interface.
+               _, err = shared.RunCommand("ip", "link", "add", "dev", 
saveData["host_name"], "link", parentName, "type", "macvtap", "mode", "bridge")
+               if err != nil {
+                       return nil, err
+               }
        }
 
+       revert.Add(func() { NetworkRemoveInterface(saveData["host_name"]) })
+
        // Set the MAC address.
        if d.config["hwaddr"] != "" {
                _, err := shared.RunCommand("ip", "link", "set", "dev", 
saveData["host_name"], "address", d.config["hwaddr"])
                if err != nil {
-                       if statusDev == "created" {
-                               NetworkRemoveInterface(saveData["host_name"])
-                       }
-
                        return nil, fmt.Errorf("Failed to set the MAC address: 
%s", err)
                }
        }
@@ -100,14 +115,18 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, 
error) {
        if d.config["mtu"] != "" {
                _, err := shared.RunCommand("ip", "link", "set", "dev", 
saveData["host_name"], "mtu", d.config["mtu"])
                if err != nil {
-                       if statusDev == "created" {
-                               NetworkRemoveInterface(saveData["host_name"])
-                       }
-
                        return nil, fmt.Errorf("Failed to set the MTU: %s", err)
                }
        }
 
+       if d.inst.Type() == instancetype.VM {
+               // Bring the interface up on host side.
+               _, err := shared.RunCommand("ip", "link", "set", "dev", 
saveData["host_name"], "up")
+               if err != nil {
+                       return nil, fmt.Errorf("Failed to bring up interface 
%s: %v", saveData["host_name"], err)
+               }
+       }
+
        err = d.volatileSet(saveData)
        if err != nil {
                return nil, err
@@ -122,6 +141,13 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, 
error) {
                {Key: "link", Value: saveData["host_name"]},
        }
 
+       if d.inst.Type() == instancetype.VM {
+               runConf.NetworkInterface = append(runConf.NetworkInterface,
+                       deviceConfig.RunConfigItem{Key: "hwaddr", Value: 
d.config["hwaddr"]},
+               )
+       }
+
+       revert.Success()
        return &runConf, nil
 }
 

From 9fc15f83510188df9dfc0031c2d72d262d8b4730 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jan 2020 18:18:45 +0000
Subject: [PATCH 4/4] lxd/instance/drivers/driver/qemu: Adds macvtap support

Uses macvtap device created by device layer to get a file handle to it and pass 
it to qemu to use.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/instance/drivers/driver_qemu.go | 60 +++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 8 deletions(-)

diff --git a/lxd/instance/drivers/driver_qemu.go 
b/lxd/instance/drivers/driver_qemu.go
index 0639b907b2..a86bc54aa6 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -657,7 +657,10 @@ func (vm *qemu) Start(stateful bool) error {
                return err
        }
 
-       confFile, err := vm.generateQemuConfigFile(qemuType, qemuConfig, 
devConfs)
+       // Define a set of files to open and pass their file descriptors to 
qemu command.
+       fdFiles := make([]string, 0)
+
+       confFile, err := vm.generateQemuConfigFile(qemuType, qemuConfig, 
devConfs, &fdFiles)
        if err != nil {
                op.Done(err)
                return err
@@ -726,8 +729,25 @@ func (vm *qemu) Start(stateful bool) error {
                args = append(args, fields...)
        }
 
-       _, err = shared.RunCommand(qemuBinary, args...)
+       cmd := exec.Command(qemuBinary, args...)
+       var stdout bytes.Buffer
+       var stderr bytes.Buffer
+       cmd.Stdout = &stdout
+       cmd.Stderr = &stderr
+
+       // Open any extra files and pass their file handles to qemu command.
+       for _, file := range fdFiles {
+               f, err := os.OpenFile(file, os.O_RDWR, 0)
+               if err != nil {
+                       return errors.Wrapf(err, "Error opening exta file %q", 
file)
+               }
+               defer f.Close() // Close file after qemu has started.
+               cmd.ExtraFiles = append(cmd.ExtraFiles, f)
+       }
+
+       err = cmd.Run()
        if err != nil {
+               err = errors.Wrapf(err, "Failed to run: %s %s: %s", qemuBinary, 
strings.Join(args, " "), strings.TrimSpace(string(stderr.Bytes())))
                op.Done(err)
                return err
        }
@@ -1180,7 +1200,7 @@ func (vm *qemu) deviceBootPriorities() (map[string]int, 
error) {
 
 // generateQemuConfigFile writes the qemu config file and returns its location.
 // It writes the config file inside the VM's log path.
-func (vm *qemu) generateQemuConfigFile(qemuType string, qemuConf string, 
devConfs []*deviceConfig.RunConfig) (string, error) {
+func (vm *qemu) generateQemuConfigFile(qemuType string, qemuConf string, 
devConfs []*deviceConfig.RunConfig, fdFiles *[]string) (string, error) {
        var sb *strings.Builder = &strings.Builder{}
 
        // Base config. This is common for all VMs and has no variables in it.
@@ -1324,7 +1344,7 @@ backend = "pty"
 
                // Add network device.
                if len(runConf.NetworkInterface) > 0 {
-                       err = vm.addNetDevConfig(sb, nicIndex, bootIndexes, 
runConf.NetworkInterface)
+                       err = vm.addNetDevConfig(sb, nicIndex, bootIndexes, 
runConf.NetworkInterface, fdFiles)
                        if err != nil {
                                return "", err
                        }
@@ -1548,26 +1568,49 @@ bootindex = "{{.bootIndex}}"
 }
 
 // addNetDevConfig adds the qemu config required for adding a network device.
-func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, bootIndexes 
map[string]int, nicConfig []deviceConfig.RunConfigItem) error {
-       var devName, devTap, devHwaddr string
+func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, bootIndexes 
map[string]int, nicConfig []deviceConfig.RunConfigItem, fdFiles *[]string) 
error {
+       var devName, nicName, devHwaddr string
+       var tapFD int
        for _, nicItem := range nicConfig {
                if nicItem.Key == "devName" {
                        devName = nicItem.Value
                } else if nicItem.Key == "link" {
-                       devTap = nicItem.Value
+                       nicName = nicItem.Value
                } else if nicItem.Key == "hwaddr" {
                        devHwaddr = nicItem.Value
                }
        }
 
+       // Detect MACVTAP interface types and figure out which tap device is 
being used.
+       // This is so we can open a file handle to the tap device and pass it 
to the qemu process.
+       if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/macvtap", nicName)) 
{
+               content, err := 
ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/ifindex", nicName))
+               if err != nil {
+                       return errors.Wrapf(err, "Error getting tap device 
ifindex")
+               }
+
+               ifindex, err := strconv.Atoi(strings.TrimSpace(string(content)))
+               if err != nil {
+                       return errors.Wrapf(err, "Error parsing tap device 
ifindex")
+               }
+
+               // Append the tap device file path to the list of files to be 
opened and passed to qemu.
+               *fdFiles = append(*fdFiles, fmt.Sprintf("/dev/tap%d", ifindex))
+               tapFD = 2 + len(*fdFiles) // Use 2+fdFiles count, as first file 
descriptor available is 3.
+       }
+
        // Devices use "lxd_" prefix indicating that this is a user named 
device.
        t := template.Must(template.New("").Parse(`
 # Network card ("{{.devName}}" device)
 [netdev "lxd_{{.devName}}"]
 type = "tap"
+{{ if ne .tapFD 0 }}
+fd = "{{.tapFD}}"
+{{ else }}
 ifname = "{{.ifName}}"
 script = "no"
 downscript = "no"
+{{ end }}
 
 [device "qemu_pcie{{.chassisIndex}}"]
 driver = "pcie-root-port"
@@ -1587,12 +1630,13 @@ bootindex = "{{.bootIndex}}"
 
        m := map[string]interface{}{
                "devName":      devName,
-               "ifName":       devTap,
+               "ifName":       nicName,
                "chassisIndex": 5 + nicIndex,
                "portIndex":    14 + nicIndex,
                "pcieAddr":     4 + nicIndex,
                "devHwaddr":    devHwaddr,
                "bootIndex":    bootIndexes[devName],
+               "tapFD":        tapFD,
        }
        return t.Execute(sb, m)
 }
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to