mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #17890 from aboch/b6
Restore deterministic IPv6 from MAC behavior on default bridge network
This commit is contained in:
commit
7a985cfafc
6 changed files with 98 additions and 20 deletions
|
@ -455,12 +455,25 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
|
||||||
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
|
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipamV6Conf *libnetwork.IpamConf
|
var (
|
||||||
|
ipamV6Conf *libnetwork.IpamConf
|
||||||
|
deferIPv6Alloc bool
|
||||||
|
)
|
||||||
if config.Bridge.FixedCIDRv6 != "" {
|
if config.Bridge.FixedCIDRv6 != "" {
|
||||||
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
|
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if ipamV6Conf == nil {
|
||||||
ipamV6Conf = &libnetwork.IpamConf{}
|
ipamV6Conf = &libnetwork.IpamConf{}
|
||||||
}
|
}
|
||||||
|
@ -485,7 +498,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
|
||||||
netlabel.GenericData: netOption,
|
netlabel.GenericData: netOption,
|
||||||
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
|
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
|
||||||
}),
|
}),
|
||||||
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf))
|
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf),
|
||||||
|
libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
|
return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
|
||||||
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
|
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
|
||||||
|
|
||||||
#get libnetwork packages
|
#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/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
|
|
|
@ -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) {
|
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"))
|
c.Assert(s.d.Start("--log-level=bogus"), check.NotNil, check.Commentf("Daemon shouldn't start with wrong log level"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,6 +450,8 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ipamV6Data) > 0 {
|
if len(ipamV6Data) > 0 {
|
||||||
|
c.AddressIPv6 = ipamV6Data[0].Pool
|
||||||
|
|
||||||
if ipamV6Data[0].Gateway != nil {
|
if ipamV6Data[0].Gateway != nil {
|
||||||
c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
|
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.
|
// We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior.
|
||||||
if !config.DefaultBridge {
|
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)
|
return d.storeDelete(config)
|
||||||
|
@ -959,13 +963,20 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
|
||||||
if endpoint.addrv6 == nil && config.EnableIPv6 {
|
if endpoint.addrv6 == nil && config.EnableIPv6 {
|
||||||
var ip6 net.IP
|
var ip6 net.IP
|
||||||
network := n.bridge.bridgeIPv6
|
network := n.bridge.bridgeIPv6
|
||||||
|
if config.AddressIPv6 != nil {
|
||||||
|
network = config.AddressIPv6
|
||||||
|
}
|
||||||
|
|
||||||
ones, _ := network.Mask.Size()
|
ones, _ := network.Mask.Size()
|
||||||
if ones <= 80 {
|
if ones > 80 {
|
||||||
ip6 = make(net.IP, len(network.IP))
|
err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network)
|
||||||
copy(ip6, network.IP)
|
return err
|
||||||
for i, h := range endpoint.macAddress {
|
}
|
||||||
ip6[i+10] = h
|
|
||||||
}
|
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}
|
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
|
// Remove port mappings. Do not stop endpoint delete on unmap failure
|
||||||
n.releasePorts(ep)
|
n.releasePorts(ep)
|
||||||
|
|
||||||
// Try removal of link. Discard error: link pair might have
|
// Try removal of link. Discard error: it is a best effort.
|
||||||
// already been deleted by sandbox delete. Make sure defer
|
// Also make sure defer does not see this error either.
|
||||||
// does not see this error either.
|
|
||||||
if link, err := netlink.LinkByName(ep.srcName); err == nil {
|
if link, err := netlink.LinkByName(ep.srcName); err == nil {
|
||||||
netlink.LinkDel(link)
|
netlink.LinkDel(link)
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,7 +737,7 @@ func (ep *endpoint) DataScope() string {
|
||||||
return ep.getNetwork().DataScope()
|
return ep.getNetwork().DataScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) assignAddress() error {
|
func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
|
||||||
var (
|
var (
|
||||||
ipam ipamapi.Ipam
|
ipam ipamapi.Ipam
|
||||||
err error
|
err error
|
||||||
|
@ -754,11 +754,18 @@ func (ep *endpoint) assignAddress() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ep.assignAddressVersion(4, ipam)
|
|
||||||
if err != nil {
|
if assignIPv4 {
|
||||||
return err
|
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 {
|
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 {
|
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 {
|
if err == nil {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
*address = addr
|
*address = addr
|
||||||
|
|
|
@ -152,6 +152,7 @@ type network struct {
|
||||||
ipamV4Info []*IpamInfo
|
ipamV4Info []*IpamInfo
|
||||||
ipamV6Info []*IpamInfo
|
ipamV6Info []*IpamInfo
|
||||||
enableIPv6 bool
|
enableIPv6 bool
|
||||||
|
postIPv6 bool
|
||||||
epCnt *endpointCnt
|
epCnt *endpointCnt
|
||||||
generic options.Generic
|
generic options.Generic
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
@ -298,6 +299,7 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
||||||
dstN.ipamType = n.ipamType
|
dstN.ipamType = n.ipamType
|
||||||
dstN.enableIPv6 = n.enableIPv6
|
dstN.enableIPv6 = n.enableIPv6
|
||||||
dstN.persist = n.persist
|
dstN.persist = n.persist
|
||||||
|
dstN.postIPv6 = n.postIPv6
|
||||||
dstN.dbIndex = n.dbIndex
|
dstN.dbIndex = n.dbIndex
|
||||||
dstN.dbExists = n.dbExists
|
dstN.dbExists = n.dbExists
|
||||||
dstN.drvOnce = n.drvOnce
|
dstN.drvOnce = n.drvOnce
|
||||||
|
@ -358,6 +360,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
||||||
netMap["generic"] = n.generic
|
netMap["generic"] = n.generic
|
||||||
}
|
}
|
||||||
netMap["persist"] = n.persist
|
netMap["persist"] = n.persist
|
||||||
|
netMap["postIPv6"] = n.postIPv6
|
||||||
if len(n.ipamV4Config) > 0 {
|
if len(n.ipamV4Config) > 0 {
|
||||||
ics, err := json.Marshal(n.ipamV4Config)
|
ics, err := json.Marshal(n.ipamV4Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -418,6 +421,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
||||||
if v, ok := netMap["persist"]; ok {
|
if v, ok := netMap["persist"]; ok {
|
||||||
n.persist = v.(bool)
|
n.persist = v.(bool)
|
||||||
}
|
}
|
||||||
|
if v, ok := netMap["postIPv6"]; ok {
|
||||||
|
n.postIPv6 = v.(bool)
|
||||||
|
}
|
||||||
if v, ok := netMap["ipamType"]; ok {
|
if v, ok := netMap["ipamType"]; ok {
|
||||||
n.ipamType = v.(string)
|
n.ipamType = v.(string)
|
||||||
} else {
|
} 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) {
|
func (n *network) processOptions(options ...NetworkOption) {
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
|
@ -655,7 +671,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
||||||
|
|
||||||
ep.processOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
||||||
if err = ep.assignAddress(); err != nil {
|
if err = ep.assignAddress(true, !n.postIPv6); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
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 {
|
if err = n.getController().updateToStore(ep); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue