Browse code

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 <estesp@linux.vnet.ibm.com> (github: estesp)

Phil Estes authored on 2015/01/28 12:03:27
Showing 2 changed files
... ...
@@ -150,6 +150,21 @@ func InitDriver(job *engine.Job) engine.Status {
150 150
 			}
151 151
 		}
152 152
 
153
+		// a bridge might exist but not have any IPv6 addr associated with it yet
154
+		// (for example, an existing Docker installation that has only been used
155
+		// with IPv4 and docker0 already is set up) In that case, we can perform
156
+		// the bridge init for IPv6 here, else we will error out below if --ipv6=true
157
+		if len(addrsv6) == 0 && enableIPv6 {
158
+			if err := setupIPv6Bridge(bridgeIPv6); err != nil {
159
+				return job.Error(err)
160
+			}
161
+			// recheck addresses now that IPv6 is setup on the bridge
162
+			addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
163
+			if err != nil {
164
+				return job.Error(err)
165
+			}
166
+		}
167
+
153 168
 		// TODO: Check if route to fixedCIDRv6 is set
154 169
 	}
155 170
 
... ...
@@ -401,21 +416,9 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error
401 401
 	}
402 402
 
403 403
 	if enableIPv6 {
404
-		// Enable IPv6 on the bridge
405
-		procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
406
-		if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
407
-			return fmt.Errorf("unable to enable IPv6 addresses on bridge: %s\n", err)
408
-		}
409
-
410
-		ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
411
-		if err != nil {
412
-			log.Errorf("BridgeIPv6 parsing failed")
404
+		if err := setupIPv6Bridge(bridgeIPv6); err != nil {
413 405
 			return err
414 406
 		}
415
-
416
-		if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
417
-			return fmt.Errorf("Unable to add private IPv6 network: %s", err)
418
-		}
419 407
 	}
420 408
 
421 409
 	if err := netlink.NetworkLinkUp(iface); err != nil {
... ...
@@ -424,6 +427,30 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error
424 424
 	return nil
425 425
 }
426 426
 
427
+func setupIPv6Bridge(bridgeIPv6 string) error {
428
+
429
+	iface, err := net.InterfaceByName(bridgeIface)
430
+	if err != nil {
431
+		return err
432
+	}
433
+	// Enable IPv6 on the bridge
434
+	procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
435
+	if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
436
+		return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
437
+	}
438
+
439
+	ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
440
+	if err != nil {
441
+		return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err)
442
+	}
443
+
444
+	if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
445
+		return fmt.Errorf("Unable to add private IPv6 network: %v", err)
446
+	}
447
+
448
+	return nil
449
+}
450
+
427 451
 func createBridgeIface(name string) error {
428 452
 	kv, err := kernel.GetKernelVersion()
429 453
 	// only set the bridge's mac address if the kernel version is > 3.3
... ...
@@ -74,7 +74,7 @@ func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
74 74
 	return netIP.Mask(network.Mask), net.IP(lastIP)
75 75
 }
76 76
 
77
-// Return the IPv4 address of a network interface
77
+// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface
78 78
 func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
79 79
 	iface, err := net.InterfaceByName(name)
80 80
 	if err != nil {