From 43b3b6ecb4f838023478c484d32957386b7dd666 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 10 Nov 2015 21:13:25 -0800 Subject: [PATCH 1/2] Vendoring libnetwork e8ebc0bf6510343c88d162db08b3d855cbbe75b9 Signed-off-by: Alessandro Boch --- hack/vendor.sh | 2 +- .../libnetwork/drivers/bridge/bridge.go | 30 ++++++++++++------- .../github.com/docker/libnetwork/endpoint.go | 23 ++++++++++---- .../github.com/docker/libnetwork/network.go | 22 +++++++++++++- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/hack/vendor.sh b/hack/vendor.sh index a250b4cc7..92808ca59 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -22,7 +22,7 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git #get libnetwork packages -clone git github.com/docker/libnetwork 5978c276ad20e104d6acd749da6ee6a8930055ae +clone git github.com/docker/libnetwork e8ebc0bf6510343c88d162db08b3d855cbbe75b9 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 6124ccb6c..8cc26f951 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -450,6 +450,8 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d } if len(ipamV6Data) > 0 { + c.AddressIPv6 = ipamV6Data[0].Pool + if ipamV6Data[0].Gateway != nil { c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway) } @@ -738,7 +740,9 @@ func (d *driver) DeleteNetwork(nid string) error { // We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior. if !config.DefaultBridge { - err = netlink.LinkDel(n.bridge.Link) + if err := netlink.LinkDel(n.bridge.Link); err != nil { + logrus.Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err) + } } return d.storeDelete(config) @@ -959,13 +963,20 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, if endpoint.addrv6 == nil && config.EnableIPv6 { var ip6 net.IP network := n.bridge.bridgeIPv6 + if config.AddressIPv6 != nil { + network = config.AddressIPv6 + } + ones, _ := network.Mask.Size() - if ones <= 80 { - ip6 = make(net.IP, len(network.IP)) - copy(ip6, network.IP) - for i, h := range endpoint.macAddress { - ip6[i+10] = h - } + if ones > 80 { + err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network) + return err + } + + ip6 = make(net.IP, len(network.IP)) + copy(ip6, network.IP) + for i, h := range endpoint.macAddress { + ip6[i+10] = h } endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask} @@ -1037,9 +1048,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error { // Remove port mappings. Do not stop endpoint delete on unmap failure n.releasePorts(ep) - // Try removal of link. Discard error: link pair might have - // already been deleted by sandbox delete. Make sure defer - // does not see this error either. + // Try removal of link. Discard error: it is a best effort. + // Also make sure defer does not see this error either. if link, err := netlink.LinkByName(ep.srcName); err == nil { netlink.LinkDel(link) } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint.go b/vendor/src/github.com/docker/libnetwork/endpoint.go index de7b652dc..02c7ba331 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint.go @@ -737,7 +737,7 @@ func (ep *endpoint) DataScope() string { return ep.getNetwork().DataScope() } -func (ep *endpoint) assignAddress() error { +func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error { var ( ipam ipamapi.Ipam err error @@ -754,11 +754,18 @@ func (ep *endpoint) assignAddress() error { if err != nil { return err } - err = ep.assignAddressVersion(4, ipam) - if err != nil { - return err + + if assignIPv4 { + if err = ep.assignAddressVersion(4, ipam); err != nil { + return err + } } - return ep.assignAddressVersion(6, ipam) + + if assignIPv6 { + err = ep.assignAddressVersion(6, ipam) + } + + return err } func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { @@ -787,7 +794,11 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { } for _, d := range ipInfo { - addr, _, err := ipam.RequestAddress(d.PoolID, nil, nil) + var prefIP net.IP + if *address != nil { + prefIP = (*address).IP + } + addr, _, err := ipam.RequestAddress(d.PoolID, prefIP, nil) if err == nil { ep.Lock() *address = addr diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index 258460284..00061ea01 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -152,6 +152,7 @@ type network struct { ipamV4Info []*IpamInfo ipamV6Info []*IpamInfo enableIPv6 bool + postIPv6 bool epCnt *endpointCnt generic options.Generic dbIndex uint64 @@ -298,6 +299,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN.ipamType = n.ipamType dstN.enableIPv6 = n.enableIPv6 dstN.persist = n.persist + dstN.postIPv6 = n.postIPv6 dstN.dbIndex = n.dbIndex dstN.dbExists = n.dbExists dstN.drvOnce = n.drvOnce @@ -358,6 +360,7 @@ func (n *network) MarshalJSON() ([]byte, error) { netMap["generic"] = n.generic } netMap["persist"] = n.persist + netMap["postIPv6"] = n.postIPv6 if len(n.ipamV4Config) > 0 { ics, err := json.Marshal(n.ipamV4Config) if err != nil { @@ -418,6 +421,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { if v, ok := netMap["persist"]; ok { n.persist = v.(bool) } + if v, ok := netMap["postIPv6"]; ok { + n.postIPv6 = v.(bool) + } if v, ok := netMap["ipamType"]; ok { n.ipamType = v.(string) } else { @@ -505,6 +511,16 @@ func NetworkOptionDriverOpts(opts map[string]string) NetworkOption { } } +// NetworkOptionDeferIPv6Alloc instructs the network to defer the IPV6 address allocation until after the endpoint has been created +// It is being provided to support the specific docker daemon flags where user can deterministically assign an IPv6 address +// to a container as combination of fixed-cidr-v6 + mac-address +// TODO: Remove this option setter once we support endpoint ipam options +func NetworkOptionDeferIPv6Alloc(enable bool) NetworkOption { + return func(n *network) { + n.postIPv6 = enable + } +} + func (n *network) processOptions(options ...NetworkOption) { for _, opt := range options { if opt != nil { @@ -655,7 +671,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi ep.processOptions(options...) - if err = ep.assignAddress(); err != nil { + if err = ep.assignAddress(true, !n.postIPv6); err != nil { return nil, err } defer func() { @@ -675,6 +691,10 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi } }() + if err = ep.assignAddress(false, n.postIPv6); err != nil { + return nil, err + } + if err = n.getController().updateToStore(ep); err != nil { return nil, err } From 095a8ac5451de25a91fc569a6633fdd8d4cabb3f Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Tue, 10 Nov 2015 21:14:05 -0800 Subject: [PATCH 2/2] Restore IPv6 from MAC on default bridge network Signed-off-by: Alessandro Boch --- daemon/daemon_unix.go | 18 ++++++++++++++++-- integration-cli/docker_cli_daemon_test.go | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index cca5691a6..e6a6c0f05 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -455,12 +455,25 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String() } - var ipamV6Conf *libnetwork.IpamConf + var ( + ipamV6Conf *libnetwork.IpamConf + deferIPv6Alloc bool + ) if config.Bridge.FixedCIDRv6 != "" { _, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6) if err != nil { return err } + + // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has + // at least 48 host bits, we need to guarantee the current behavior where the containers' + // IPv6 addresses will be constructed based on the containers' interface MAC address. + // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints + // on this network until after the driver has created the endpoint and returned the + // constructed address. Libnetwork will then reserve this address with the ipam driver. + ones, _ := fCIDRv6.Mask.Size() + deferIPv6Alloc = ones <= 80 + if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{} } @@ -485,7 +498,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e netlabel.GenericData: netOption, netlabel.EnableIPv6: config.Bridge.EnableIPv6, }), - libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf)) + libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf), + libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) if err != nil { return fmt.Errorf("Error creating default \"bridge\" network: %v", err) } diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index f8e175523..21d9e6710 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -377,6 +377,29 @@ func (s *DockerSuite) TestDaemonIPv6FixedCIDR(c *check.C) { } } +// TestDaemonIPv6FixedCIDRAndMac checks that when the daemon is started with ipv6 fixed CIDR +// the running containers are given a an IPv6 address derived from the MAC address and the ipv6 fixed CIDR +func (s *DockerSuite) TestDaemonIPv6FixedCIDRAndMac(c *check.C) { + err := setupV6() + c.Assert(err, checker.IsNil) + + d := NewDaemon(c) + + err = d.StartWithBusybox("--ipv6", "--fixed-cidr-v6='2001:db8:1::/64'") + c.Assert(err, checker.IsNil) + defer d.Stop() + + out, err := d.Cmd("run", "-itd", "--name=ipv6test", "--mac-address", "AA:BB:CC:DD:EE:FF", "busybox") + c.Assert(err, checker.IsNil) + + out, err = d.Cmd("inspect", "--format", "'{{.NetworkSettings.Networks.bridge.GlobalIPv6Address}}'", "ipv6test") + c.Assert(err, checker.IsNil) + c.Assert(strings.Trim(out, " \r\n'"), checker.Equals, "2001:db8:1::aabb:ccdd:eeff") + + err = teardownV6() + c.Assert(err, checker.IsNil) +} + func (s *DockerDaemonSuite) TestDaemonLogLevelWrong(c *check.C) { c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level")) }