[lxc-devel] [lxd/master] lxd/container: network up hook for network limits

tomponline on Github lxc-bot at linuxcontainers.org
Tue Apr 16 11:21:50 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 444 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190416/3bdd5e2a/attachment.bin>
-------------- next part --------------
From acefbaa3a2766f36795c456b10430e23e7fed01f Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Tue, 16 Apr 2019 12:09:05 +0100
Subject: [PATCH] lxd/container: Moves network limits to be run as a network up
 hook rather than container start hook

Signed-off-by: tomponline <tomp at tomp.uk>
---
 lxd/api_internal.go  | 26 ++++++++++++++++++++++++++
 lxd/container.go     |  1 +
 lxd/container_lxc.go | 40 +++++++++++++++++-----------------------
 lxd/main_callhook.go |  4 +++-
 4 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index dfec648fc4..38ea706cd9 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -33,6 +33,7 @@ var apiInternal = []Command{
 	internalReadyCmd,
 	internalShutdownCmd,
 	internalContainerOnStartCmd,
+	internalContainerOnNetworkUpCmd,
 	internalContainerOnStopCmd,
 	internalContainersCmd,
 	internalSQLCmd,
@@ -64,6 +65,11 @@ var internalContainerOnStopCmd = Command{
 	get:  internalContainerOnStop,
 }
 
+var internalContainerOnNetworkUpCmd = Command{
+	name: "containers/{id}/onnetwork-up",
+	get:  internalContainerOnNetworkUp,
+}
+
 var internalSQLCmd = Command{
 	name: "sql",
 	get:  internalSQLGet,
@@ -146,6 +152,26 @@ func internalContainerOnStop(d *Daemon, r *http.Request) Response {
 	return EmptySyncResponse
 }
 
+func internalContainerOnNetworkUp(d *Daemon, r *http.Request) Response {
+	id, err := strconv.Atoi(mux.Vars(r)["id"])
+	if err != nil {
+		return SmartError(err)
+	}
+
+	c, err := containerLoadById(d.State(), id)
+	if err != nil {
+		return SmartError(err)
+	}
+
+	err = c.OnNetworkUp(queryParam(r, "device"), queryParam(r, "host_name"))
+	if err != nil {
+		logger.Error("The network up script failed", log.Ctx{"container": c.Name(), "err": err})
+		return SmartError(err)
+	}
+
+	return EmptySyncResponse
+}
+
 type internalSQLDump struct {
 	Text string `json:"text" yaml:"text"`
 }
diff --git a/lxd/container.go b/lxd/container.go
index 354aae4011..3bafd25006 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -634,6 +634,7 @@ type container interface {
 	// Hooks
 	OnStart() error
 	OnStop(target string) error
+	OnNetworkUp(deviceName string, hostVeth string) error
 
 	// Properties
 	Id() int
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 98ad0fefaa..6bcea40ae4 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1634,6 +1634,11 @@ func (c *containerLXC) initLXC(config bool) error {
 				}
 			}
 
+			err = lxcSetConfigItem(cc, fmt.Sprintf("%s.%d.script.up", networkKeyPrefix, networkidx), fmt.Sprintf("%s callhook %s %d network-up %s", c.state.OS.ExecPath, shared.VarPath(""), c.id, k))
+			if err != nil {
+				return err
+			}
+
 			err = lxcSetConfigItem(cc, fmt.Sprintf("%s.%d.flags", networkKeyPrefix, networkidx), "up")
 			if err != nil {
 				return err
@@ -2710,14 +2715,6 @@ func (c *containerLXC) OnStart() error {
 		if m["limits.max"] == "" && m["limits.ingress"] == "" && m["limits.egress"] == "" {
 			continue
 		}
-
-		go func(c *containerLXC, name string, m types.Device) {
-			c.fromHook = false
-			err = c.setNetworkLimits(name, m)
-			if err != nil {
-				logger.Error("Failed to apply network limits", log.Ctx{"container": c.name, "err": err})
-			}
-		}(c, name, m)
 	}
 
 	// Record current state
@@ -3014,6 +3011,13 @@ func (c *containerLXC) OnStop(target string) error {
 	return nil
 }
 
+// OnNetworkUp is called by the LXD callhook when the LXC network up script is run.
+func (c *containerLXC) OnNetworkUp(deviceName string, hostName string) error {
+	device := c.expandedDevices[deviceName]
+	device["host_name"] = hostName
+	return c.setNetworkLimits(deviceName, device)
+}
+
 // Freezer functions
 func (c *containerLXC) Freeze() error {
 	ctxMap := log.Ctx{
@@ -4850,6 +4854,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 				if needsUpdate {
 					// Refresh tc limits
+					m["host_name"] = c.getHostInterface(m["name"])
 					err = c.setNetworkLimits(k, m)
 					if err != nil {
 						return err
@@ -8580,26 +8585,15 @@ func (c *containerLXC) getHostInterface(name string) string {
 }
 
 func (c *containerLXC) setNetworkLimits(name string, m types.Device) error {
+	var err error
 	// We can only do limits on some network type
 	if m["nictype"] != "bridged" && m["nictype"] != "p2p" {
 		return fmt.Errorf("Network limits are only supported on bridged and p2p interfaces")
 	}
 
-	// Check that the container is running
-	if !c.IsRunning() {
-		return fmt.Errorf("Can't set network limits on stopped container")
-	}
-
-	// Fill in some fields from volatile
-	m, err := c.fillNetworkDevice(name, m)
-	if err != nil {
-		return nil
-	}
-
-	// Look for the host side interface name
-	veth := c.getHostInterface(m["name"])
-	if veth == "" {
-		return fmt.Errorf("LXC doesn't know about this device and the host_name property isn't set, can't find host side veth name")
+	veth := m["host_name"]
+	if !shared.PathExists(fmt.Sprintf("/sys/class/net/%s", veth)) {
+		return fmt.Errorf("Unknown or missing host side veth: %s", veth)
 	}
 
 	// Apply max limit
diff --git a/lxd/main_callhook.go b/lxd/main_callhook.go
index a453798f3e..e586c46a6b 100644
--- a/lxd/main_callhook.go
+++ b/lxd/main_callhook.go
@@ -17,7 +17,7 @@ type cmdCallhook struct {
 
 func (c *cmdCallhook) Command() *cobra.Command {
 	cmd := &cobra.Command{}
-	cmd.Use = "callhook <path> <id> <state>"
+	cmd.Use = "callhook <path> <id> <hook>"
 	cmd.Short = "Call container lifecycle hook in LXD"
 	cmd.Long = `Description:
   Call container lifecycle hook in LXD
@@ -72,6 +72,8 @@ func (c *cmdCallhook) Run(cmd *cobra.Command, args []string) error {
 			target = "unknown"
 		}
 		url = fmt.Sprintf("%s?target=%s", url, target)
+	} else if state == "network-up" {
+		url = fmt.Sprintf("%s?device=%s&host_name=%s", url, args[3], os.Getenv("LXC_NET_PEER"))
 	}
 
 	// Setup the request


More information about the lxc-devel mailing list