Browse Source

Merge pull request #853 from aboch/cv6

Check if present before programming IPv6 in bridge
Madhu Venugopal 9 years ago
parent
commit
60bbe6e2d4

+ 16 - 0
libnetwork/drivers/bridge/interface.go

@@ -1,6 +1,7 @@
 package bridge
 
 import (
+	"fmt"
 	"net"
 
 	"github.com/vishvananda/netlink"
@@ -61,3 +62,18 @@ func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
 	}
 	return v4addr[0], v6addr, nil
 }
+
+func (i *bridgeInterface) programIPv6Address() error {
+	_, nlAddressList, err := i.addresses()
+	if err != nil {
+		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: fmt.Errorf("failed to retrieve address list: %v", err)}
+	}
+	nlAddr := netlink.Addr{IPNet: i.bridgeIPv6}
+	if findIPv6Address(nlAddr, nlAddressList) {
+		return nil
+	}
+	if err := netlink.AddrAdd(i.Link, &nlAddr); err != nil {
+		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
+	}
+	return nil
+}

+ 11 - 18
libnetwork/drivers/bridge/setup_ipv6.go

@@ -7,6 +7,7 @@ import (
 	"os"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 )
 
@@ -22,9 +23,8 @@ const (
 func init() {
 	// We allow ourselves to panic in this special case because we indicate a
 	// failure to parse a compile-time define constant.
-	if ip, netw, err := net.ParseCIDR(bridgeIPv6Str); err == nil {
-		bridgeIPv6 = &net.IPNet{IP: ip, Mask: netw.Mask}
-	} else {
+	var err error
+	if bridgeIPv6, err = types.ParseCIDR(bridgeIPv6Str); err != nil {
 		panic(fmt.Sprintf("Cannot parse default bridge IPv6 address %q: %v", bridgeIPv6Str, err))
 	}
 }
@@ -42,31 +42,24 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
 		}
 	}
 
-	_, addrsv6, err := i.addresses()
-	if err != nil {
-		return err
-	}
-
-	// Add the default link local ipv6 address if it doesn't exist
-	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
-		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
-			return &IPv6AddrAddError{IP: bridgeIPv6, Err: err}
-		}
-	}
-
 	// Store bridge network and default gateway
 	i.bridgeIPv6 = bridgeIPv6
 	i.gatewayIPv6 = i.bridgeIPv6.IP
 
+	if err := i.programIPv6Address(); err != nil {
+		return err
+	}
+
 	if config.AddressIPv6 == nil {
 		return nil
 	}
 
-	// Store and program user specified bridge network and network gateway
+	// Store the user specified bridge network and network gateway and program it
 	i.bridgeIPv6 = config.AddressIPv6
 	i.gatewayIPv6 = config.AddressIPv6.IP
-	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: i.bridgeIPv6}); err != nil {
-		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
+
+	if err := i.programIPv6Address(); err != nil {
+		return err
 	}
 
 	// Setting route to global IPv6 subnet

+ 10 - 5
libnetwork/drivers/bridge/setup_verify.go

@@ -1,6 +1,8 @@
 package bridge
 
 import (
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 )
 
@@ -27,11 +29,14 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e
 		return (*IPv6AddrNoMatchError)(bridgeIPv6)
 	}
 
-	// By this time we have either configured a new bridge with an IP address
-	// or made sure an existing bridge's IP matches the configuration
-	// Now is the time to cache these states in the bridgeInterface.
-	i.bridgeIPv4 = addrv4.IPNet
-	i.bridgeIPv6 = bridgeIPv6
+	// Release any residual IPv6 address that might be there because of older daemon instances
+	for _, addrv6 := range addrsv6 {
+		if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
+			if err := netlink.AddrDel(i.Link, &addrv6); err != nil {
+				log.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
+			}
+		}
+	}
 
 	return nil
 }