[lxc-devel] [lxd/master] Device post stop hook

tomponline on Github lxc-bot at linuxcontainers.org
Mon Aug 5 11:11:37 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1792 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190805/8421d04a/attachment-0001.bin>
-------------- next part --------------
From 4d08285c9e54704756a4005534c0398c145f4e0d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:03:11 +0100
Subject: [PATCH 01/11] container/lxc: Restructures deviceStop to support post
 stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_lxc.go | 147 +++++++++++++++++++++++--------------------
 1 file changed, 80 insertions(+), 67 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 26e60b9fbc..8e1723e5e2 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1821,8 +1821,8 @@ func (c *containerLXC) initLXC(config bool) error {
 	return nil
 }
 
-// runPostStartHooks executes the callback functions after container has started.
-func (c *containerLXC) runPostStartHooks(hooks []func() error) error {
+// runHooks executes the callback functions returned from a function.
+func (c *containerLXC) runHooks(hooks []func() error) error {
 	// Run any post start hooks.
 	if len(hooks) > 0 {
 		for _, hook := range hooks {
@@ -1893,13 +1893,13 @@ func (c *containerLXC) deviceStart(deviceName string, rawConfig map[string]strin
 	if isRunning && runConfig != nil {
 		// If network interface settings returned, then attach NIC to container.
 		if len(runConfig.NetworkInterface) > 0 {
-			err = c.deviceAttachNIC(configCopy, runConfig)
+			err = c.deviceAttachNIC(configCopy, runConfig.NetworkInterface)
 			if err != nil {
 				return nil, err
 			}
 		}
 
-		err = c.runPostStartHooks(runConfig.PostStartHooks)
+		err = c.runHooks(runConfig.PostHooks)
 		if err != nil {
 			return nil, err
 		}
@@ -1909,9 +1909,9 @@ func (c *containerLXC) deviceStart(deviceName string, rawConfig map[string]strin
 }
 
 // deviceAttachNIC live attaches a NIC device to a container.
-func (c *containerLXC) deviceAttachNIC(configCopy map[string]string, runConfig *device.RunConfig) error {
+func (c *containerLXC) deviceAttachNIC(configCopy map[string]string, netIF []device.RunConfigItem) error {
 	devName := ""
-	for _, dev := range runConfig.NetworkInterface {
+	for _, dev := range netIF {
 		if dev.Key == "link" {
 			devName = dev.Value
 			break
@@ -1959,76 +1959,89 @@ func (c *containerLXC) deviceStop(deviceName string, rawConfig map[string]string
 		return err
 	}
 
+	// An empty netns path means we haven't been called from the LXC stop hook, so are running.
 	if canHotPlug, _ := d.CanHotPlug(); stopHookNetnsPath == "" && !canHotPlug {
 		return fmt.Errorf("Device cannot be stopped when container is running")
 	}
 
-	// Ensure nic and infiniband devices are detached.
-	if shared.StringInSlice(rawConfig["type"], []string{"nic", "infiniband"}) {
-		hostName := c.localConfig[fmt.Sprintf("volatile.%s.host_name", deviceName)]
-		hostNameExists := hostName != "" && shared.PathExists(fmt.Sprintf("/sys/class/net/%s", hostName))
-
-		// If container is running, perform live detach of interface back to host.
-		if stopHookNetnsPath == "" {
-			// For some reason, having network config confuses detach, so get our own go-lxc struct.
-			cname := project.Prefix(c.Project(), c.Name())
-			cc, err := lxc.NewContainer(cname, c.state.OS.LxcPath)
+	runConfig, err := d.Stop()
+	if err != nil {
+		return err
+	}
+
+	if runConfig != nil {
+		// If network interface settings returned, then detach NIC from container.
+		if len(runConfig.NetworkInterface) > 0 {
+			err = c.deviceDetachNIC(configCopy, runConfig.NetworkInterface, stopHookNetnsPath)
 			if err != nil {
 				return err
 			}
-			defer cc.Release()
+		}
 
-			// Get interfaces inside container.
-			ifaces, err := cc.Interfaces()
-			if err != nil {
-				return fmt.Errorf("Failed to list network interfaces: %v", err)
-			}
+		err = c.runHooks(runConfig.PostHooks)
+		if err != nil {
+			return err
+		}
+	}
 
-			// Remove the interface from the container if it exists inside container.
-			if shared.StringInSlice(configCopy["name"], ifaces) {
-				detachHostName := hostName
+	return nil
+}
 
-				// If the host_name is empty or already exists, we need to detach to a
-				// random device name, so generate one here.
-				if hostName == "" || hostNameExists {
-					detachHostName = device.NetworkRandomDevName("lxd")
-				}
+// deviceDetachNIC detaches a NIC device from a container.
+func (c *containerLXC) deviceDetachNIC(configCopy map[string]string, netIF []device.RunConfigItem, stopHookNetnsPath string) error {
+	// Get requested device name to detach interface back to on the host.
+	devName := ""
+	for _, dev := range netIF {
+		if dev.Key == "link" {
+			devName = dev.Value
+			break
+		}
+	}
 
-				err = cc.DetachInterfaceRename(configCopy["name"], detachHostName)
-				if err != nil {
-					return errors.Wrapf(err, "Failed to detach interface: %s to %s", configCopy["name"], detachHostName)
-				}
+	if devName == "" {
+		return fmt.Errorf("Device didn't provide a link property to use")
+	}
 
-				// If we have detached the device to a random host_name it is our
-				// responsibility to delete the device as there is no other record of this.
-				if hostName == "" || hostNameExists {
-					// Attempt to remove device, but don't return on failure as Stop()
-					// still needs to be called.
-					err := device.NetworkRemoveInterface(detachHostName)
-					if err != nil {
-						logger.Errorf("Error removing interface: %s: %v", detachHostName, err)
-					}
-				}
-			}
-		} else {
-			// Currently liblxc does not move devices back to the host on stop that were added
-			// after the the container was started. For this reason we utilise the lxc.hook.stop
-			// hook so that we can capture the netns path, enter the namespace and move the nics
-			// back to the host and rename them if liblxc hasn't already done it.
-			// We can only move back devices that have an expected host_name record and where
-			// that device doesn't already exist on the host.
-			if hostName != "" && !hostNameExists {
-				err := c.detachInterfaceRename(stopHookNetnsPath, configCopy["name"], hostName)
-				if err != nil {
-					return errors.Wrapf(err, "Failed to detach interface: %s to %s", configCopy["name"], hostName)
-				}
-			}
+	// If container is running, perform live detach of interface back to host.
+	if stopHookNetnsPath == "" {
+		// For some reason, having network config confuses detach, so get our own go-lxc struct.
+		cname := project.Prefix(c.Project(), c.Name())
+		cc, err := lxc.NewContainer(cname, c.state.OS.LxcPath)
+		if err != nil {
+			return err
 		}
-	}
+		defer cc.Release()
 
-	err = d.Stop()
-	if err != nil {
-		return err
+		// Get interfaces inside container.
+		ifaces, err := cc.Interfaces()
+		if err != nil {
+			return fmt.Errorf("Failed to list network interfaces: %v", err)
+		}
+
+		// If interface doesn't exist inside container, cannot proceed.
+		if !shared.StringInSlice(configCopy["name"], ifaces) {
+			return nil
+		}
+
+		err = cc.DetachInterfaceRename(configCopy["name"], devName)
+		if err != nil {
+			return errors.Wrapf(err, "Failed to detach interface: %s to %s", configCopy["name"], devName)
+		}
+	} else {
+		// Currently liblxc does not move devices back to the host on stop that were added
+		// after the the container was started. For this reason we utilise the lxc.hook.stop
+		// hook so that we can capture the netns path, enter the namespace and move the nics
+		// back to the host and rename them if liblxc hasn't already done it.
+		// We can only move back devices that have an expected host_name record and where
+		// that device doesn't already exist on the host as if a device exists on the host
+		// we can't know whether that is because liblxc has moved it back already or whether
+		// it is a conflicting device.
+		if !shared.PathExists(fmt.Sprintf("/sys/class/net/%s", devName)) {
+			err := c.detachInterfaceRename(stopHookNetnsPath, configCopy["name"], devName)
+			if err != nil {
+				return errors.Wrapf(err, "Failed to detach interface: %s to %s", configCopy["name"], devName)
+			}
+		}
 	}
 
 	return nil
@@ -2537,8 +2550,8 @@ func (c *containerLXC) startCommon() (string, []func() error, error) {
 				}
 
 				// Add any post start hooks.
-				if len(runConfig.PostStartHooks) > 0 {
-					postStartHooks = append(postStartHooks, runConfig.PostStartHooks...)
+				if len(runConfig.PostHooks) > 0 {
+					postStartHooks = append(postStartHooks, runConfig.PostHooks...)
 				}
 
 				continue
@@ -2732,7 +2745,7 @@ func (c *containerLXC) Start(stateful bool) error {
 		}
 
 		// Run any post start hooks.
-		err = c.runPostStartHooks(postStartHooks)
+		err = c.runHooks(postStartHooks)
 		if err != nil {
 			// Attempt to stop container.
 			op.Done(err)
@@ -2800,7 +2813,7 @@ func (c *containerLXC) Start(stateful bool) error {
 	}
 
 	// Run any post start hooks.
-	err = c.runPostStartHooks(postStartHooks)
+	err = c.runHooks(postStartHooks)
 	if err != nil {
 		// Attempt to stop container.
 		op.Done(err)
@@ -5711,7 +5724,7 @@ func (c *containerLXC) Migrate(args *CriuMigrationArgs) error {
 
 		if migrateErr == nil {
 			// Run any post start hooks.
-			err := c.runPostStartHooks(postStartHooks)
+			err := c.runHooks(postStartHooks)
 			if err != nil {
 				// Attempt to stop container.
 				c.Stop(false)

From 9e3e7273247e76f071a83f9be8d5833035310543 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:03:40 +0100
Subject: [PATCH 02/11] device: Updates interface for Stop() to return
 RunConfig

For supporting post stop hooks.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/device.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lxd/device/device.go b/lxd/device/device.go
index 4281bdcd3e..bd481de53e 100644
--- a/lxd/device/device.go
+++ b/lxd/device/device.go
@@ -46,7 +46,8 @@ type Device interface {
 
 	// Stop performs any host-side cleanup required when a device is removed from an instance,
 	// either due to unplugging it from a running instance or instance is being shutdown.
-	Stop() error
+	// Returns run-time configuration needed for detaching the device from the instance.
+	Stop() (*RunConfig, error)
 
 	// Remove performs any host-side cleanup when an instance is removed from an instance.
 	Remove() error

From 342526cee818f329c2d76c6e445389d833d359e8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:04:12 +0100
Subject: [PATCH 03/11] device/device/runconfig: Renames PostStartHooks to
 PostHooks

So it can be used with both Start() and Stop() device functions.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/device_runconfig.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/device/device_runconfig.go b/lxd/device/device_runconfig.go
index 831dcef688..9bf5633ff3 100644
--- a/lxd/device/device_runconfig.go
+++ b/lxd/device/device_runconfig.go
@@ -6,8 +6,8 @@ type RunConfigItem struct {
 	Value string
 }
 
-// RunConfig represents LXD defined run-time config used for device setup.
+// RunConfig represents LXD defined run-time config used for device setup/cleanup.
 type RunConfig struct {
-	NetworkInterface []RunConfigItem
-	PostStartHooks   []func() error
+	NetworkInterface []RunConfigItem // Network interface configuration settings.
+	PostHooks        []func() error  // Functions to be run after device attach/detach.
 }

From 9f6b910d425ba42b10f984ea9f893a1114504e3c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:04:49 +0100
Subject: [PATCH 04/11] device/nic/bridged: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_bridged.go | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 1dcd37713b..b2fe08a569 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -229,7 +229,16 @@ func (d *nicBridged) Update(oldConfig config.Device, isRunning bool) error {
 }
 
 // Stop is run when the device is removed from the instance.
-func (d *nicBridged) Stop() error {
+func (d *nicBridged) Stop() (*RunConfig, error) {
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicBridged) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"host_name": "",
 	})

From 2ce181faf7f2ac8de9f6f1a6d31848be1766ddb2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:05:19 +0100
Subject: [PATCH 05/11] device/nic/p2p: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_p2p.go | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/lxd/device/nic_p2p.go b/lxd/device/nic_p2p.go
index ea6909c816..7f37af4a16 100644
--- a/lxd/device/nic_p2p.go
+++ b/lxd/device/nic_p2p.go
@@ -116,8 +116,17 @@ func (d *nicP2P) Update(oldConfig config.Device, isRunning bool) error {
 	return nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *nicP2P) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *nicP2P) Stop() (*RunConfig, error) {
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicP2P) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"host_name": "",
 	})

From a8de4b7115540c5acdfd42460119f53695aac12f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:56:31 +0100
Subject: [PATCH 06/11] device/nic/vlan: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_ipvlan.go | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/lxd/device/nic_ipvlan.go b/lxd/device/nic_ipvlan.go
index c380d549d3..e67565d7af 100644
--- a/lxd/device/nic_ipvlan.go
+++ b/lxd/device/nic_ipvlan.go
@@ -208,8 +208,17 @@ func (d *nicIPVLAN) setupParentSysctls(parentName string) error {
 	return nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *nicIPVLAN) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *nicIPVLAN) Stop() (*RunConfig, error) {
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicIPVLAN) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"last_state.created": "",
 	})

From ab55b694bf6297d4e1a39ed47ef982eba95d8c59 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:56:45 +0100
Subject: [PATCH 07/11] device/nic/macvlan: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_macvlan.go | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index 1aabbeb660..2f75467374 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -109,8 +109,21 @@ func (d *nicMACVLAN) Start() (*RunConfig, error) {
 	return &runConf, nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *nicMACVLAN) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *nicMACVLAN) Stop() (*RunConfig, error) {
+	v := d.volatileGet()
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+		NetworkInterface: []RunConfigItem{
+			{Key: "link", Value: v["host_name"]},
+		},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicMACVLAN) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"host_name":          "",
 		"last_state.hwaddr":  "",

From 55414948cd940e0c0ed1b5719f95d67cd11370cc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:56:57 +0100
Subject: [PATCH 08/11] device/nic/physical: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_physical.go | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index 5faa6a2ec4..092ae01e8c 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -115,8 +115,21 @@ func (d *nicPhysical) Start() (*RunConfig, error) {
 	return &runConf, nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *nicPhysical) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *nicPhysical) Stop() (*RunConfig, error) {
+	v := d.volatileGet()
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+		NetworkInterface: []RunConfigItem{
+			{Key: "link", Value: v["host_name"]},
+		},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicPhysical) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"host_name":          "",
 		"last_state.hwaddr":  "",

From 6cdb29e2dd6f7e7f7df3528017058c171fe5e226 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:57:10 +0100
Subject: [PATCH 09/11] device/nic/sriov: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/nic_sriov.go | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index ebad700af6..37cb536917 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -141,8 +141,21 @@ func (d *nicSRIOV) Start() (*RunConfig, error) {
 	return &runConf, nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *nicSRIOV) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *nicSRIOV) Stop() (*RunConfig, error) {
+	v := d.volatileGet()
+	runConfig := RunConfig{
+		PostHooks: []func() error{d.postStop},
+		NetworkInterface: []RunConfigItem{
+			{Key: "link", Value: v["host_name"]},
+		},
+	}
+
+	return &runConfig, nil
+}
+
+// postStop is run after the device is removed from the instance.
+func (d *nicSRIOV) postStop() error {
 	defer d.volatileSet(map[string]string{
 		"host_name":                "",
 		"last_state.hwaddr":        "",

From 409743eb7fe64a67cd0ff7634510bb47cae55da5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:57:25 +0100
Subject: [PATCH 10/11] device/proxy: Updates for post stop hooks

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/proxy.go | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lxd/device/proxy.go b/lxd/device/proxy.go
index dbb3ad7fed..2d0c3cef88 100644
--- a/lxd/device/proxy.go
+++ b/lxd/device/proxy.go
@@ -140,7 +140,7 @@ func (d *proxy) Start() (*RunConfig, error) {
 
 	// Proxy devices have to be setup once the container is running.
 	runConf := RunConfig{}
-	runConf.PostStartHooks = []func() error{
+	runConf.PostHooks = []func() error{
 		func() error {
 			if shared.IsTrue(d.config["nat"]) {
 				return d.setupNAT()
@@ -226,8 +226,8 @@ func (d *proxy) checkProcStarted(logPath string) (bool, error) {
 	return false, nil
 }
 
-// Stop is run when the device is removed from the container.
-func (d *proxy) Stop() error {
+// Stop is run when the device is removed from the instance.
+func (d *proxy) Stop() (*RunConfig, error) {
 	// Remove possible iptables entries
 	iptables.ContainerClear("ipv4", fmt.Sprintf("%s (%s)", d.instance.Name(), d.name), "nat")
 	iptables.ContainerClear("ipv6", fmt.Sprintf("%s (%s)", d.instance.Name(), d.name), "nat")
@@ -237,15 +237,15 @@ func (d *proxy) Stop() error {
 
 	if !shared.PathExists(devPath) {
 		// There's no proxy process if NAT is enabled
-		return nil
+		return nil, nil
 	}
 
 	err := d.killProxyProc(devPath)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	return nil
+	return nil, nil
 }
 
 func (d *proxy) setupNAT() error {

From daeffea60e3fae5fb329ffe62a01d624dec5fedd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 5 Aug 2019 11:57:45 +0100
Subject: [PATCH 11/11] test: Updates NIC tests to check for volatile key
 cleanup

Also makes variable naming more consistent.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/container_devices_nic_bridged.sh  |  7 ++
 ...container_devices_nic_bridged_filtering.sh |  6 ++
 test/suites/container_devices_nic_ipvlan.sh   | 65 ++++++++++--------
 test/suites/container_devices_nic_macvlan.sh  | 68 +++++++++++--------
 test/suites/container_devices_nic_p2p.sh      |  8 ++-
 test/suites/container_devices_nic_physical.sh |  6 +-
 test/suites/container_devices_nic_sriov.sh    |  5 ++
 7 files changed, 103 insertions(+), 62 deletions(-)

diff --git a/test/suites/container_devices_nic_bridged.sh b/test/suites/container_devices_nic_bridged.sh
index 88ec2d6cf5..2a6fdee16b 100644
--- a/test/suites/container_devices_nic_bridged.sh
+++ b/test/suites/container_devices_nic_bridged.sh
@@ -283,6 +283,13 @@ test_container_devices_nic_bridged() {
     false
   fi
 
+  # Check volatile cleanup on stop.
+  lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
+
   # Test DHCP lease clearance.
   lxc delete "${ctName}" -f
   lxc launch testimage "${ctName}" -p "${ctName}"
diff --git a/test/suites/container_devices_nic_bridged_filtering.sh b/test/suites/container_devices_nic_bridged_filtering.sh
index 23ace8c2b7..997b74b0b9 100644
--- a/test/suites/container_devices_nic_bridged_filtering.sh
+++ b/test/suites/container_devices_nic_bridged_filtering.sh
@@ -274,6 +274,12 @@ test_container_devices_nic_bridged_filtering() {
       false
   fi
 
+  # Check volatile cleanup on stop.
+  if lxc config show "${ctPrefix}A" | grep volatile.eth0 | grep -v volatile.eth0.hwaddr ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
+
   # Set static MAC so that SLAAC address is derived predictably and check it is applied to static config.
   lxc config device unset "${ctPrefix}A" eth0 ipv6.address
   lxc config device set "${ctPrefix}A" eth0 hwaddr 00:16:3e:92:f3:c1
diff --git a/test/suites/container_devices_nic_ipvlan.sh b/test/suites/container_devices_nic_ipvlan.sh
index 811d2122f4..c77e32165d 100644
--- a/test/suites/container_devices_nic_ipvlan.sh
+++ b/test/suites/container_devices_nic_ipvlan.sh
@@ -7,67 +7,72 @@ test_container_devices_nic_ipvlan() {
     return
   fi
 
-  ct_name="nt$$"
+  ctName="nt$$"
   ipRand=$(shuf -i 0-9 -n 1)
 
   # Test ipvlan support to offline container (hot plugging not supported).
-  ip link add "${ct_name}" type dummy
+  ip link add "${ctName}" type dummy
 
   # Record how many nics we started with.
   startNicCount=$(find /sys/class/net | wc -l)
 
   # Check that starting IPVLAN container.
-  sysctl net.ipv6.conf."${ct_name}".proxy_ndp=1
-  sysctl net.ipv6.conf."${ct_name}".forwarding=1
-  sysctl net.ipv4.conf."${ct_name}".forwarding=1
-  lxc init testimage "${ct_name}"
-  lxc config device add "${ct_name}" eth0 nic \
+  sysctl net.ipv6.conf."${ctName}".proxy_ndp=1
+  sysctl net.ipv6.conf."${ctName}".forwarding=1
+  sysctl net.ipv4.conf."${ctName}".forwarding=1
+  lxc init testimage "${ctName}"
+  lxc config device add "${ctName}" eth0 nic \
     nictype=ipvlan \
-    parent=${ct_name} \
+    parent=${ctName} \
     ipv4.address="192.0.2.1${ipRand}" \
     ipv6.address="2001:db8::1${ipRand}" \
     mtu=1400
-  lxc start "${ct_name}"
+  lxc start "${ctName}"
 
   # Check custom MTU is applied.
-  if ! lxc exec "${ct_name}" -- ip link show eth0 | grep "mtu 1400" ; then
+  if ! lxc exec "${ctName}" -- ip link show eth0 | grep "mtu 1400" ; then
     echo "mtu invalid"
     false
   fi
 
   #Spin up another container with multiple IPs.
-  lxc init testimage "${ct_name}2"
-  lxc config device add "${ct_name}2" eth0 nic \
+  lxc init testimage "${ctName}2"
+  lxc config device add "${ctName}2" eth0 nic \
     nictype=ipvlan \
-    parent=${ct_name} \
+    parent=${ctName} \
     ipv4.address="192.0.2.2${ipRand}, 192.0.2.3${ipRand}" \
     ipv6.address="2001:db8::2${ipRand}, 2001:db8::3${ipRand}"
-  lxc start "${ct_name}2"
+  lxc start "${ctName}2"
 
   # Check comms between containers.
-  lxc exec "${ct_name}" -- ping -c2 -W1 "192.0.2.2${ipRand}"
-  lxc exec "${ct_name}" -- ping -c2 -W1 "192.0.2.3${ipRand}"
-  lxc exec "${ct_name}" -- ping6 -c2 -W1 "2001:db8::2${ipRand}"
-  lxc exec "${ct_name}" -- ping6 -c2 -W1 "2001:db8::3${ipRand}"
-  lxc exec "${ct_name}2" -- ping -c2 -W1 "192.0.2.1${ipRand}"
-  lxc exec "${ct_name}2" -- ping6 -c2 -W1 "2001:db8::1${ipRand}"
-  lxc stop -f "${ct_name}2"
+  lxc exec "${ctName}" -- ping -c2 -W1 "192.0.2.2${ipRand}"
+  lxc exec "${ctName}" -- ping -c2 -W1 "192.0.2.3${ipRand}"
+  lxc exec "${ctName}" -- ping6 -c2 -W1 "2001:db8::2${ipRand}"
+  lxc exec "${ctName}" -- ping6 -c2 -W1 "2001:db8::3${ipRand}"
+  lxc exec "${ctName}2" -- ping -c2 -W1 "192.0.2.1${ipRand}"
+  lxc exec "${ctName}2" -- ping6 -c2 -W1 "2001:db8::1${ipRand}"
+  lxc stop -f "${ctName}2"
 
   # Check IPVLAN ontop of VLAN parent.
-  lxc stop -f "${ct_name}"
-  lxc config device set "${ct_name}" eth0 vlan 1234
-  lxc start "${ct_name}"
+  lxc stop -f "${ctName}"
+  lxc config device set "${ctName}" eth0 vlan 1234
+  lxc start "${ctName}"
 
   # Check VLAN interface created
-  if ! grep "1" "/sys/class/net/${ct_name}.1234/carrier" ; then
+  if ! grep "1" "/sys/class/net/${ctName}.1234/carrier" ; then
     echo "vlan interface not created"
     false
   fi
 
-  lxc stop -f "${ct_name}"
+  # Check volatile cleanup on stop.
+  lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 | grep -v volatile.eth0.hwaddr | grep -v volatile.eth0.name ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
 
   # Check parent device is still up.
-  if ! grep "1" "/sys/class/net/${ct_name}/carrier" ; then
+  if ! grep "1" "/sys/class/net/${ctName}/carrier" ; then
     echo "parent is down"
     false
   fi
@@ -80,7 +85,7 @@ test_container_devices_nic_ipvlan() {
   fi
 
   # Cleanup ipvlan checks
-  lxc delete "${ct_name}" -f
-  lxc delete "${ct_name}2" -f
-  ip link delete "${ct_name}" type dummy
+  lxc delete "${ctName}" -f
+  lxc delete "${ctName}2" -f
+  ip link delete "${ctName}" type dummy
 }
diff --git a/test/suites/container_devices_nic_macvlan.sh b/test/suites/container_devices_nic_macvlan.sh
index 3530e311e5..1070be7bbb 100644
--- a/test/suites/container_devices_nic_macvlan.sh
+++ b/test/suites/container_devices_nic_macvlan.sh
@@ -2,86 +2,94 @@ test_container_devices_nic_macvlan() {
   ensure_import_testimage
   ensure_has_localhost_remote "${LXD_ADDR}"
 
-  ct_name="nt$$"
+  ctName="nt$$"
   ipRand=$(shuf -i 0-9 -n 1)
 
   # Create dummy interface for use as parent.
-  ip link add "${ct_name}" type dummy
-  ip link set "${ct_name}" up
+  ip link add "${ctName}" type dummy
+  ip link set "${ctName}" up
 
   # Record how many nics we started with.
   startNicCount=$(find /sys/class/net | wc -l)
 
   # Test pre-launch profile config is applied at launch.
-  lxc profile copy default "${ct_name}"
+  lxc profile copy default "${ctName}"
 
   # Modifiy profile nictype and parent in atomic operation to ensure validation passes.
-  lxc profile show "${ct_name}" | sed  "s/nictype: p2p/nictype: macvlan\n    parent: ${ct_name}/" | lxc profile edit "${ct_name}"
-  lxc profile device set "${ct_name}" eth0 mtu "1400"
+  lxc profile show "${ctName}" | sed  "s/nictype: p2p/nictype: macvlan\n    parent: ${ctName}/" | lxc profile edit "${ctName}"
+  lxc profile device set "${ctName}" eth0 mtu "1400"
 
-  lxc launch testimage "${ct_name}" -p "${ct_name}"
-  lxc exec "${ct_name}" -- ip addr add "192.0.2.1${ipRand}/24" dev eth0
-  lxc exec "${ct_name}" -- ip addr add "2001:db8::1${ipRand}/64" dev eth0
+  lxc launch testimage "${ctName}" -p "${ctName}"
+  lxc exec "${ctName}" -- ip addr add "192.0.2.1${ipRand}/24" dev eth0
+  lxc exec "${ctName}" -- ip addr add "2001:db8::1${ipRand}/64" dev eth0
 
   # Check custom MTU is applied if feature available in LXD.
   if lxc info | grep 'network_phys_macvlan_mtu: "true"' ; then
-    if ! lxc exec "${ct_name}" -- ip link show eth0 | grep "mtu 1400" ; then
+    if ! lxc exec "${ctName}" -- ip link show eth0 | grep "mtu 1400" ; then
       echo "mtu invalid"
       false
     fi
   fi
 
   #Spin up another container with multiple IPs.
-  lxc launch testimage "${ct_name}2" -p "${ct_name}"
-  lxc exec "${ct_name}2" -- ip addr add "192.0.2.2${ipRand}/24" dev eth0
-  lxc exec "${ct_name}2" -- ip addr add "2001:db8::2${ipRand}/64" dev eth0
+  lxc launch testimage "${ctName}2" -p "${ctName}"
+  lxc exec "${ctName}2" -- ip addr add "192.0.2.2${ipRand}/24" dev eth0
+  lxc exec "${ctName}2" -- ip addr add "2001:db8::2${ipRand}/64" dev eth0
 
   # Check comms between containers.
-  lxc exec "${ct_name}" -- ping -c2 -W1 "192.0.2.2${ipRand}"
-  lxc exec "${ct_name}" -- ping6 -c2 -W1 "2001:db8::2${ipRand}"
-  lxc exec "${ct_name}2" -- ping -c2 -W1 "192.0.2.1${ipRand}"
-  lxc exec "${ct_name}2" -- ping6 -c2 -W1 "2001:db8::1${ipRand}"
+  lxc exec "${ctName}" -- ping -c2 -W1 "192.0.2.2${ipRand}"
+  lxc exec "${ctName}" -- ping6 -c2 -W1 "2001:db8::2${ipRand}"
+  lxc exec "${ctName}2" -- ping -c2 -W1 "192.0.2.1${ipRand}"
+  lxc exec "${ctName}2" -- ping6 -c2 -W1 "2001:db8::1${ipRand}"
 
   # Test hot plugging a container nic with different settings to profile with the same name.
-  lxc config device add "${ct_name}" eth0 nic \
+  lxc config device add "${ctName}" eth0 nic \
     nictype=macvlan \
     name=eth0 \
-    parent="${ct_name}" \
+    parent="${ctName}" \
     mtu=1401
 
   # Check custom MTU is applied on hot-plug.
-  if ! lxc exec "${ct_name}" -- ip link show eth0 | grep "mtu 1401" ; then
+  if ! lxc exec "${ctName}" -- ip link show eth0 | grep "mtu 1401" ; then
     echo "mtu invalid"
     false
   fi
 
-  lxc config device remove "${ct_name}" eth0
+  # Check volatile cleanup on stop.
+  lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 | grep -v volatile.eth0.hwaddr ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
+
+  lxc start "${ctName}"
+  lxc config device remove "${ctName}" eth0
 
   # Test hot plugging macvlan device based on vlan parent.
-  lxc config device add "${ct_name}" eth0 nic \
+  lxc config device add "${ctName}" eth0 nic \
     nictype=macvlan \
-    parent="${ct_name}" \
+    parent="${ctName}" \
     name=eth0 \
     vlan=10 \
     mtu=1402
 
   # Check custom MTU is applied.
-  if ! lxc exec "${ct_name}" -- ip link show eth0 | grep "mtu 1402" ; then
+  if ! lxc exec "${ctName}" -- ip link show eth0 | grep "mtu 1402" ; then
     echo "mtu invalid"
     false
   fi
 
   # Check VLAN interface created
-  if ! grep "1" "/sys/class/net/${ct_name}.10/carrier" ; then
+  if ! grep "1" "/sys/class/net/${ctName}.10/carrier" ; then
     echo "vlan interface not created"
     false
   fi
 
   # Remove device from container, this should also remove created VLAN parent device.
-  lxc config device remove "${ct_name}" eth0
+  lxc config device remove "${ctName}" eth0
 
   # Check parent device is still up.
-  if ! grep "1" "/sys/class/net/${ct_name}/carrier" ; then
+  if ! grep "1" "/sys/class/net/${ctName}/carrier" ; then
     echo "parent is down"
     false
   fi
@@ -94,7 +102,7 @@ test_container_devices_nic_macvlan() {
   fi
 
   # Cleanup.
-  lxc delete "${ct_name}" -f
-  lxc delete "${ct_name}2" -f
-  ip link delete "${ct_name}" type dummy
+  lxc delete "${ctName}" -f
+  lxc delete "${ctName}2" -f
+  ip link delete "${ctName}" type dummy
 }
diff --git a/test/suites/container_devices_nic_p2p.sh b/test/suites/container_devices_nic_p2p.sh
index a6db37b026..01bbae94a3 100644
--- a/test/suites/container_devices_nic_p2p.sh
+++ b/test/suites/container_devices_nic_p2p.sh
@@ -244,8 +244,14 @@ test_container_devices_nic_p2p() {
     false
   fi
 
-  # Now add a nic to a stopped container with routes.
+  # Check volatile cleanup on stop.
   lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 | grep -v volatile.eth0.hwaddr ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
+
+  # Now add a nic to a stopped container with routes.
   lxc config device add "${ctName}" eth0 nic \
     nictype=p2p \
     ipv4.routes="192.0.2.2${ipRand}/32" \
diff --git a/test/suites/container_devices_nic_physical.sh b/test/suites/container_devices_nic_physical.sh
index ab05624b2b..a027dc392b 100644
--- a/test/suites/container_devices_nic_physical.sh
+++ b/test/suites/container_devices_nic_physical.sh
@@ -40,8 +40,12 @@ test_container_devices_nic_physical() {
     false
   fi
 
-  # Stop container and check MTU is restored.
+  # Check volatile cleanup on stop.
   lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
 
   # Check original MTU is restored on physical device.
   if lxc info | grep 'network_phys_macvlan_mtu: "true"' ; then
diff --git a/test/suites/container_devices_nic_sriov.sh b/test/suites/container_devices_nic_sriov.sh
index 8c3ccc9cc5..8ae6429d99 100644
--- a/test/suites/container_devices_nic_sriov.sh
+++ b/test/suites/container_devices_nic_sriov.sh
@@ -72,7 +72,12 @@ test_container_devices_nic_sriov() {
     fi
   fi
 
+  # Check volatile cleanup on stop.
   lxc stop -f "${ctName}"
+  if lxc config show "${ctName}" | grep volatile.eth0 | grep -v volatile.eth0.hwaddr | grep -v volatile.eth0.name ; then
+    echo "unexpected volatile key remains"
+    false
+  fi
 
   # Set custom MAC
   lxc config device set "${ctName}" eth0 hwaddr "${ctMAC1}"


More information about the lxc-devel mailing list