[lxc-devel] [lxd/master] networks: Save & restore container routes on network start

tomponline on Github lxc-bot at linuxcontainers.org
Wed Jun 12 21:18:17 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190612/b028e288/attachment-0001.bin>
-------------- next part --------------
From 8c0ba0d7649858b3b0f75d6221c42ef7684581b1 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 12 Jun 2019 22:14:29 +0100
Subject: [PATCH 1/3] networks_utils: Adds container boot route functions

networkListBootRoutesV4
networkListBootRoutesV6
networkApplyBootRoutesV4
networkApplyBootRoutesV6

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

diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 83688d1285..7fd48a5caa 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -1379,3 +1379,67 @@ func networkSetDevMAC(devName string, mac string) error {
 
 	return nil
 }
+
+// networkListBootRoutesV4 returns a list of IPv4 boot routes on a named network device.
+func networkListBootRoutesV4(devName string) ([]string, error) {
+	routes := []string{}
+	cmd := exec.Command("ip", "-4", "route", "show", "dev", devName, "proto", "boot")
+	ipOut, err := cmd.StdoutPipe()
+	if err != nil {
+		return routes, err
+	}
+	cmd.Start()
+	scanner := bufio.NewScanner(ipOut)
+	for scanner.Scan() {
+		route := scanner.Text()
+		routes = append(routes, route)
+	}
+	cmd.Wait()
+	return routes, nil
+}
+
+// networkListBootRoutesV6 returns a list of IPv6 boot routes on a named network device.
+func networkListBootRoutesV6(devName string) ([]string, error) {
+	routes := []string{}
+	cmd := exec.Command("ip", "-6", "route", "show", "dev", devName, "proto", "boot")
+	ipOut, err := cmd.StdoutPipe()
+	if err != nil {
+		return routes, err
+	}
+	cmd.Start()
+	scanner := bufio.NewScanner(ipOut)
+	for scanner.Scan() {
+		route := scanner.Text()
+		routes = append(routes, route)
+	}
+	cmd.Wait()
+	return routes, nil
+}
+
+// networkApplyBootRoutesV4 applies a list of IPv4 boot routes to a named network device.
+func networkApplyBootRoutesV4(devName string, routes []string) error {
+	for _, route := range routes {
+		cmd := []string{"-4", "route", "replace", "dev", devName, "proto", "boot"}
+		cmd = append(cmd, strings.Fields(route)...)
+		_, err := shared.RunCommand("ip", cmd...)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// networkApplyBootRoutesV6 applies a list of IPv6 boot routes to a named network device.
+func networkApplyBootRoutesV6(devName string, routes []string) error {
+	for _, route := range routes {
+		cmd := []string{"-6", "route", "replace", "dev", devName, "proto", "boot"}
+		cmd = append(cmd, strings.Fields(route)...)
+		_, err := shared.RunCommand("ip", cmd...)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}

From 4a4b9a9ca79bf258a76e86544653b8bda037b3df Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 12 Jun 2019 22:15:23 +0100
Subject: [PATCH 2/3] container_lxc: Makes static routes use boot proto to
 differentiate network level routes

This allows networks to be restarted and container routes re-applied.

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

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 433838e0c6..f5cad36e9e 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -9120,22 +9120,22 @@ func (c *containerLXC) setNetworkRoutes(deviceName string, m types.Device, oldDe
 		routeDev = m["parent"]
 	}
 
-	// Add additional IPv4 routes
+	// Add additional IPv4 routes (using boot proto to avoid conflicts with network static routes)
 	if m["ipv4.routes"] != "" {
 		for _, route := range strings.Split(m["ipv4.routes"], ",") {
 			route = strings.TrimSpace(route)
-			_, err := shared.RunCommand("ip", "-4", "route", "add", route, "dev", routeDev, "proto", "static")
+			_, err := shared.RunCommand("ip", "-4", "route", "add", route, "dev", routeDev, "proto", "boot")
 			if err != nil {
 				return err
 			}
 		}
 	}
 
-	// Add additional IPv6 routes
+	// Add additional IPv6 routes (using boot proto to avoid conflicts with network static routes)
 	if m["ipv6.routes"] != "" {
 		for _, route := range strings.Split(m["ipv6.routes"], ",") {
 			route = strings.TrimSpace(route)
-			_, err := shared.RunCommand("ip", "-6", "route", "add", route, "dev", routeDev, "proto", "static")
+			_, err := shared.RunCommand("ip", "-6", "route", "add", route, "dev", routeDev, "proto", "boot")
 			if err != nil {
 				return err
 			}
@@ -9174,7 +9174,7 @@ func (c *containerLXC) removeNetworkRoutes(deviceName string, m types.Device) {
 	if m["ipv4.routes"] != "" {
 		for _, route := range strings.Split(m["ipv4.routes"], ",") {
 			route = strings.TrimSpace(route)
-			_, err := shared.RunCommand("ip", "-4", "route", "flush", route, "dev", routeDev, "proto", "static")
+			_, err := shared.RunCommand("ip", "-4", "route", "flush", route, "dev", routeDev, "proto", "boot")
 			if err != nil {
 				logger.Errorf("Failed to remove static route: %s to %s: %s", route, routeDev, err)
 			}
@@ -9185,7 +9185,7 @@ func (c *containerLXC) removeNetworkRoutes(deviceName string, m types.Device) {
 	if m["ipv6.routes"] != "" {
 		for _, route := range strings.Split(m["ipv6.routes"], ",") {
 			route = strings.TrimSpace(route)
-			_, err := shared.RunCommand("ip", "-6", "route", "flush", route, "dev", routeDev, "proto", "static")
+			_, err := shared.RunCommand("ip", "-6", "route", "flush", route, "dev", routeDev, "proto", "boot")
 			if err != nil {
 				logger.Errorf("Failed to remove static route: %s to %s: %s", route, routeDev, err)
 			}

From 7d2332f728bb09f0668e21fa7c2330657bfc0ec3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 12 Jun 2019 22:16:17 +0100
Subject: [PATCH 3/3] networks: Saves & restores container (boot proto) routes
 on interface when starting

Fixes #5832

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

diff --git a/lxd/networks.go b/lxd/networks.go
index 48e625cdc2..acaf05653a 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -1206,12 +1206,25 @@ func (n *network) Start() error {
 		return err
 	}
 
+	// Snapshot container specific IPv4 routes (added with boot proto) before removing IPv4 addresses.
+	// This is because the kernel removes any static routes on an interface when all addresses removed.
+	ctRoutes, err := networkListBootRoutesV4(n.name)
+	if err != nil {
+		return err
+	}
+
 	// Flush all IPv4 addresses and routes
 	_, err = shared.RunCommand("ip", "-4", "addr", "flush", "dev", n.name, "scope", "global")
 	if err != nil {
 		return err
 	}
 
+	// Restore container specific IPv4 routes to interface.
+	err = networkApplyBootRoutesV4(n.name, ctRoutes)
+	if err != nil {
+		return err
+	}
+
 	_, err = shared.RunCommand("ip", "-4", "route", "flush", "dev", n.name, "proto", "static")
 	if err != nil {
 		return err
@@ -1375,12 +1388,25 @@ func (n *network) Start() error {
 		return err
 	}
 
+	// Snapshot container specific IPv6 routes (added with boot proto) before removing IPv6 addresses.
+	// This is because the kernel removes any static routes on an interface when all addresses removed.
+	ctRoutes, err = networkListBootRoutesV6(n.name)
+	if err != nil {
+		return err
+	}
+
 	// Flush all IPv6 addresses and routes
 	_, err = shared.RunCommand("ip", "-6", "addr", "flush", "dev", n.name, "scope", "global")
 	if err != nil {
 		return err
 	}
 
+	// Restore container specific IPv6 routes to interface.
+	err = networkApplyBootRoutesV6(n.name, ctRoutes)
+	if err != nil {
+		return err
+	}
+
 	_, err = shared.RunCommand("ip", "-6", "route", "flush", "dev", n.name, "proto", "static")
 	if err != nil {
 		return err


More information about the lxc-devel mailing list