diff --git a/libnetwork/drivers/bridge/interface.go b/libnetwork/drivers/bridge/interface.go index b05f2ea804..cdf68836fc 100644 --- a/libnetwork/drivers/bridge/interface.go +++ b/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 +} diff --git a/libnetwork/drivers/bridge/setup_ipv6.go b/libnetwork/drivers/bridge/setup_ipv6.go index 2613b3e95a..3f07a0af8f 100644 --- a/libnetwork/drivers/bridge/setup_ipv6.go +++ b/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 diff --git a/libnetwork/drivers/bridge/setup_verify.go b/libnetwork/drivers/bridge/setup_verify.go index 6d4d66982c..4564d46ded 100644 --- a/libnetwork/drivers/bridge/setup_verify.go +++ b/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 }