[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