From 0c8d17b5c1a142bc09abe1105d985e76db6f225d Mon Sep 17 00:00:00 2001 From: Phil Estes Date: Tue, 27 Jan 2015 22:03:27 -0500 Subject: [PATCH] Fix bridge initialization for IPv6 if IPv4-only docker0 exists This fixes the daemon's failure to start when setting --ipv6=true for the first time without deleting `docker0` bridge from a prior use with only IPv4 addressing. The addition of the IPv6 bridge address is factored out into a separate initialization routine which is called even if the bridge exists but no IPv6 addresses are found. Docker-DCO-1.1-Signed-off-by: Phil Estes (github: estesp) --- daemon/networkdriver/bridge/driver.go | 53 ++++++++++++++++++++------- daemon/networkdriver/utils.go | 2 +- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index 0d3f27517d..f331f17244 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -150,6 +150,21 @@ func InitDriver(job *engine.Job) engine.Status { } } + // a bridge might exist but not have any IPv6 addr associated with it yet + // (for example, an existing Docker installation that has only been used + // with IPv4 and docker0 already is set up) In that case, we can perform + // the bridge init for IPv6 here, else we will error out below if --ipv6=true + if len(addrsv6) == 0 && enableIPv6 { + if err := setupIPv6Bridge(bridgeIPv6); err != nil { + return job.Error(err) + } + // recheck addresses now that IPv6 is setup on the bridge + addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) + if err != nil { + return job.Error(err) + } + } + // TODO: Check if route to fixedCIDRv6 is set } @@ -401,21 +416,9 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error } if enableIPv6 { - // Enable IPv6 on the bridge - procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6" - if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil { - return fmt.Errorf("unable to enable IPv6 addresses on bridge: %s\n", err) - } - - ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6) - if err != nil { - log.Errorf("BridgeIPv6 parsing failed") + if err := setupIPv6Bridge(bridgeIPv6); err != nil { return err } - - if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil { - return fmt.Errorf("Unable to add private IPv6 network: %s", err) - } } if err := netlink.NetworkLinkUp(iface); err != nil { @@ -424,6 +427,30 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error return nil } +func setupIPv6Bridge(bridgeIPv6 string) error { + + iface, err := net.InterfaceByName(bridgeIface) + if err != nil { + return err + } + // Enable IPv6 on the bridge + procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6" + if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil { + return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err) + } + + ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6) + if err != nil { + return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err) + } + + if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil { + return fmt.Errorf("Unable to add private IPv6 network: %v", err) + } + + return nil +} + func createBridgeIface(name string) error { kv, err := kernel.GetKernelVersion() // only set the bridge's mac address if the kernel version is > 3.3 diff --git a/daemon/networkdriver/utils.go b/daemon/networkdriver/utils.go index 833744b57e..9f0c88cd5e 100644 --- a/daemon/networkdriver/utils.go +++ b/daemon/networkdriver/utils.go @@ -74,7 +74,7 @@ func NetworkRange(network *net.IPNet) (net.IP, net.IP) { return netIP.Mask(network.Mask), net.IP(lastIP) } -// Return the IPv4 address of a network interface +// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) { iface, err := net.InterfaceByName(name) if err != nil {