diff --git a/docs/userguide/networking/get-started-overlay.md b/docs/userguide/networking/get-started-overlay.md index 708684e2da..17e840c52f 100644 --- a/docs/userguide/networking/get-started-overlay.md +++ b/docs/userguide/networking/get-started-overlay.md @@ -16,7 +16,6 @@ network. Docker Engine supports multi-host networking out-of-the-box through the `overlay` network driver. Unlike `bridge` networks, overlay networks require some pre-existing conditions before you can create one. These conditions are: -* A host with a 3.16 kernel version or higher. * Access to a key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores. * A cluster of hosts with connectivity to the key-value store. * A properly configured Engine `daemon` on each host in the cluster. @@ -46,7 +45,7 @@ key-value stores. This example uses Consul. 1. Log into a system prepared with the prerequisite Docker Engine, Docker Machine, and VirtualBox software. -2. Provision a VirtualBox machine called `mh-keystore`. +2. Provision a VirtualBox machine called `mh-keystore`. $ docker-machine create -d virtualbox mh-keystore diff --git a/hack/vendor.sh b/hack/vendor.sh index f6832193d2..c447312b01 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -23,7 +23,7 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith clone git github.com/docker/go-units v0.2.0 #get libnetwork packages -clone git github.com/docker/libnetwork bbd6e6d8ca1e7c9b42f6f53277b0bde72847ff90 +clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436 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/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index be9b726a28..c1aa6bb9e1 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -121,7 +121,8 @@ type driverData struct { } type ipamData struct { - driver ipamapi.Ipam + driver ipamapi.Ipam + capability *ipamapi.Capability // default address spaces are provided by ipam driver at registration time defaultLocalAddressSpace, defaultGlobalAddressSpace string } @@ -306,7 +307,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, return nil } -func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error { +func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error { if !config.IsValidName(name) { return ErrInvalidName(name) } @@ -322,7 +323,7 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err) } c.Lock() - c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS} + c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps} c.Unlock() log.Debugf("Registering ipam driver: %q", name) @@ -330,6 +331,14 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error return nil } +func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error { + return c.registerIpamDriver(name, driver, &ipamapi.Capability{}) +} + +func (c *controller) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error { + return c.registerIpamDriver(name, driver, caps) +} + // NewNetwork creates a new network of the specified network type. The options // are network specific and modeled in a generic way. func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) { diff --git a/vendor/src/github.com/docker/libnetwork/default_gateway.go b/vendor/src/github.com/docker/libnetwork/default_gateway.go index 139242c6a5..d9277ba577 100644 --- a/vendor/src/github.com/docker/libnetwork/default_gateway.go +++ b/vendor/src/github.com/docker/libnetwork/default_gateway.go @@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool { if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" { continue } + if ep.getNetwork().Internal() { + return false + } if ep.joinInfo.disableGatewayService { return false } 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 7991c6f67c..04f5a4c81b 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -490,6 +490,12 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati config.EnableIPv6 = val.(bool) } + if val, ok := option[netlabel.Internal]; ok { + if internal, ok := val.(bool); ok && internal { + return nil, &driverapi.ErrNotImplemented{} + } + } + // Finally validate the configuration if err = config.Validate(); err != nil { return nil, err diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go index f7a536adb0..aa6c8eba4c 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go @@ -157,6 +157,6 @@ func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) { } func isRunningInContainer() bool { - _, err := os.Stat("/.dockerinit") + _, err := os.Stat("/.dockerenv") return !os.IsNotExist(err) } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go index 5ce53dd879..2613b3e95a 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go @@ -62,6 +62,13 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error { return nil } + // Store and program user specified bridge network and network gateway + 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} + } + // Setting route to global IPv6 subnet logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName) err = netlink.RouteAdd(&netlink.Route{ diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go new file mode 100644 index 0000000000..0607548140 --- /dev/null +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go @@ -0,0 +1,131 @@ +package overlay + +import ( + "fmt" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/iptables" +) + +const globalChain = "DOCKER-OVERLAY" + +var filterOnce sync.Once + +func rawIPTables(args ...string) error { + if output, err := iptables.Raw(args...); err != nil { + return fmt.Errorf("unable to add overlay filter: %v", err) + } else if len(output) != 0 { + return fmt.Errorf("unable to add overlay filter: %s", string(output)) + } + + return nil +} + +func chainExists(cname string) bool { + if _, err := iptables.Raw("-L", cname); err != nil { + return false + } + + return true +} + +func setupGlobalChain() { + if err := rawIPTables("-N", globalChain); err != nil { + logrus.Debugf("could not create global overlay chain: %v", err) + } + + if err := rawIPTables("-A", globalChain, "-j", "RETURN"); err != nil { + logrus.Debugf("could not install default return chain in the overlay global chain: %v", err) + } +} + +func setNetworkChain(cname string, remove bool) error { + // Initialize the onetime global overlay chain + filterOnce.Do(setupGlobalChain) + + exists := chainExists(cname) + + opt := "-N" + // In case of remove, make sure to flush the rules in the chain + if remove && exists { + if err := rawIPTables("-F", cname); err != nil { + return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err) + } + opt = "-X" + } + + if (!remove && !exists) || (remove && exists) { + if err := rawIPTables(opt, cname); err != nil { + return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err) + } + } + + if !remove { + if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") { + if err := rawIPTables("-A", cname, "-j", "DROP"); err != nil { + return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err) + } + } + } + + return nil +} + +func addNetworkChain(cname string) error { + return setNetworkChain(cname, false) +} + +func removeNetworkChain(cname string) error { + return setNetworkChain(cname, true) +} + +func setFilters(cname, brName string, remove bool) error { + opt := "-I" + if remove { + opt = "-D" + } + + // Everytime we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains + if !remove { + for _, chain := range []string{"OUTPUT", "FORWARD"} { + exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain) + if exists { + if err := rawIPTables("-D", chain, "-j", globalChain); err != nil { + return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err) + } + } + + if err := rawIPTables("-I", chain, "-j", globalChain); err != nil { + return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err) + } + } + } + + // Insert/Delete the rule to jump to per-bridge chain + exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname) + if (!remove && !exists) || (remove && exists) { + if err := rawIPTables(opt, globalChain, "-o", brName, "-j", cname); err != nil { + return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err) + } + } + + exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT") + if (!remove && exists) || (remove && !exists) { + return nil + } + + if err := rawIPTables(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil { + return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err) + } + + return nil +} + +func addFilters(cname, brName string) error { + return setFilters(cname, brName, false) +} + +func removeFilters(cname, brName string) error { + return setFilters(cname, brName, true) +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go index e67757b4f0..0a891c0e5e 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net" + "os" "sync" "syscall" @@ -12,11 +13,17 @@ import ( "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/resolvconf" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" "github.com/vishvananda/netlink/nl" ) +var ( + hostMode bool + hostModeOnce sync.Once +) + type networkTable map[string]*network type subnet struct { @@ -87,22 +94,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat return nil } -/* func (d *driver) createNetworkfromStore(nid string) (*network, error) { - n := &network{ - id: nid, - driver: d, - endpoints: endpointTable{}, - once: &sync.Once{}, - subnets: []*subnet{}, - } - - err := d.store.GetObject(datastore.Key(n.Key()...), n) - if err != nil { - return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err) - } - return n, nil -}*/ - func (d *driver) DeleteNetwork(nid string) error { if nid == "" { return fmt.Errorf("invalid network id") @@ -171,24 +162,110 @@ func (n *network) destroySandbox() { } for _, s := range n.subnets { + if hostMode { + if err := removeFilters(n.id[:12], s.brName); err != nil { + logrus.Warnf("Could not remove overlay filters: %v", err) + } + } + if s.vxlanName != "" { - err := deleteVxlan(s.vxlanName) + err := deleteInterface(s.vxlanName) if err != nil { logrus.Warnf("could not cleanup sandbox properly: %v", err) } } } + + if hostMode { + if err := removeNetworkChain(n.id[:12]); err != nil { + logrus.Warnf("could not remove network chain: %v", err) + } + } + sbox.Destroy() n.setSandbox(nil) } } -func (n *network) initSubnetSandbox(s *subnet) error { - // create a bridge and vxlan device for this subnet and move it to the sandbox - brName, err := netutils.GenerateIfaceName("bridge", 7) - if err != nil { - return err +func setHostMode() { + if os.Getenv("_OVERLAY_HOST_MODE") != "" { + hostMode = true + return } + + err := createVxlan("testvxlan", 1) + if err != nil { + logrus.Errorf("Failed to create testvxlan interface: %v", err) + return + } + + defer deleteInterface("testvxlan") + + path := "/proc/self/ns/net" + f, err := os.OpenFile(path, os.O_RDONLY, 0) + if err != nil { + logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err) + return + } + defer f.Close() + + nsFD := f.Fd() + + iface, err := netlink.LinkByName("testvxlan") + if err != nil { + logrus.Errorf("Failed to get link testvxlan: %v", err) + return + } + + // If we are not able to move the vxlan interface to a namespace + // then fallback to host mode + if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil { + hostMode = true + } +} + +func (n *network) generateVxlanName(s *subnet) string { + return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5] +} + +func (n *network) generateBridgeName(s *subnet) string { + return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5] +} + +func isOverlap(nw *net.IPNet) bool { + var nameservers []string + + if rc, err := resolvconf.Get(); err == nil { + nameservers = resolvconf.GetNameserversAsCIDR(rc.Content) + } + + if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil { + return true + } + + if err := netutils.CheckRouteOverlaps(nw); err != nil { + return true + } + + return false +} + +func (n *network) initSubnetSandbox(s *subnet) error { + brName := n.generateBridgeName(s) + vxlanName := n.generateVxlanName(s) + + if hostMode { + // Try to delete stale bridge interface if it exists + deleteInterface(brName) + // Try to delete the vxlan interface by vni if already present + deleteVxlanByVNI(n.vxlanID(s)) + + if isOverlap(s.subnetIP) { + return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String()) + } + } + + // create a bridge and vxlan device for this subnet and move it to the sandbox sbox := n.sandbox() if err := sbox.AddInterface(brName, "br", @@ -197,7 +274,7 @@ func (n *network) initSubnetSandbox(s *subnet) error { return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err) } - vxlanName, err := createVxlan(n.vxlanID(s)) + err := createVxlan(vxlanName, n.vxlanID(s)) if err != nil { return err } @@ -207,6 +284,12 @@ func (n *network) initSubnetSandbox(s *subnet) error { return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.String(), err) } + if hostMode { + if err := addFilters(n.id[:12], brName); err != nil { + return err + } + } + n.Lock() s.vxlanName = vxlanName s.brName = brName @@ -220,8 +303,16 @@ func (n *network) initSandbox() error { n.initEpoch++ n.Unlock() + hostModeOnce.Do(setHostMode) + + if hostMode { + if err := addNetworkChain(n.id[:12]); err != nil { + return err + } + } + sbox, err := osl.NewSandbox( - osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true) + osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), !hostMode) if err != nil { return fmt.Errorf("could not create network sandbox: %v", err) } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go index 5bb257bf51..42c44b9675 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go @@ -47,14 +47,9 @@ func createVethPair() (string, string, error) { return name1, name2, nil } -func createVxlan(vni uint32) (string, error) { +func createVxlan(name string, vni uint32) error { defer osl.InitOSContext()() - name, err := netutils.GenerateIfaceName("vxlan", 7) - if err != nil { - return "", fmt.Errorf("error generating vxlan name: %v", err) - } - vxlan := &netlink.Vxlan{ LinkAttrs: netlink.LinkAttrs{Name: name}, VxlanId: int(vni), @@ -66,23 +61,45 @@ func createVxlan(vni uint32) (string, error) { } if err := netlink.LinkAdd(vxlan); err != nil { - return "", fmt.Errorf("error creating vxlan interface: %v", err) - } - - return name, nil -} - -func deleteVxlan(name string) error { - defer osl.InitOSContext()() - - link, err := netlink.LinkByName(name) - if err != nil { - return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err) - } - - if err := netlink.LinkDel(link); err != nil { - return fmt.Errorf("error deleting vxlan interface: %v", err) + return fmt.Errorf("error creating vxlan interface: %v", err) } return nil } + +func deleteInterface(name string) error { + defer osl.InitOSContext()() + + link, err := netlink.LinkByName(name) + if err != nil { + return fmt.Errorf("failed to find interface with name %s: %v", name, err) + } + + if err := netlink.LinkDel(link); err != nil { + return fmt.Errorf("error deleting interface with name %s: %v", name, err) + } + + return nil +} + +func deleteVxlanByVNI(vni uint32) error { + defer osl.InitOSContext()() + + links, err := netlink.LinkList() + if err != nil { + return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err) + } + + for _, l := range links { + if l.Type() == "vxlan" && l.(*netlink.Vxlan).VxlanId == int(vni) { + err = netlink.LinkDel(l) + if err != nil { + return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err) + } + + return nil + } + } + + return fmt.Errorf("could not find a vxlan interface to delete with id %d", vni) +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go index 982310d7a2..9e5eba4013 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go @@ -51,7 +51,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { d := &driver{ networks: networkTable{}, peerDb: peerNetworkMap{ - mp: map[string]peerMap{}, + mp: map[string]*peerMap{}, }, config: config, } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go index 22a677d8ba..c820da9f05 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go @@ -26,7 +26,7 @@ type peerMap struct { } type peerNetworkMap struct { - mp map[string]peerMap + mp map[string]*peerMap sync.Mutex } @@ -138,7 +138,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { - d.peerDb.mp[nid] = peerMap{ + d.peerDb.mp[nid] = &peerMap{ mp: make(map[string]peerEntry), } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint.go b/vendor/src/github.com/docker/libnetwork/endpoint.go index 524287fc8f..d5f38c51a2 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint.go @@ -748,11 +748,8 @@ func (ep *endpoint) DataScope() string { return ep.getNetwork().DataScope() } -func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error { - var ( - ipam ipamapi.Ipam - err error - ) +func (ep *endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool) error { + var err error n := ep.getNetwork() if n.Type() == "host" || n.Type() == "null" { @@ -761,11 +758,6 @@ func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error { log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name()) - ipam, err = n.getController().getIpamDriver(n.ipamType) - if err != nil { - return err - } - if assignIPv4 { if err = ep.assignAddressVersion(4, ipam); err != nil { return err diff --git a/vendor/src/github.com/docker/libnetwork/ipam/allocator.go b/vendor/src/github.com/docker/libnetwork/ipam/allocator.go index 1ca9127cc2..be8b4ac029 100644 --- a/vendor/src/github.com/docker/libnetwork/ipam/allocator.go +++ b/vendor/src/github.com/docker/libnetwork/ipam/allocator.go @@ -486,21 +486,28 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres // DumpDatabase dumps the internal info func (a *Allocator) DumpDatabase() string { a.Lock() - defer a.Unlock() + aspaces := make(map[string]*addrSpace, len(a.addrSpaces)) + for as, aSpace := range a.addrSpaces { + aspaces[as] = aSpace + } + a.Unlock() var s string - for as, aSpace := range a.addrSpaces { + for as, aSpace := range aspaces { s = fmt.Sprintf("\n\n%s Config", as) aSpace.Lock() for k, config := range aSpace.subnets { s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config)) + if config.Range == nil { + a.retrieveBitmask(k, config.Pool) + } } aSpace.Unlock() } s = fmt.Sprintf("%s\n\nBitmasks", s) for k, bm := range a.addresses { - s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected())) + s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%s: %s", k, bm)) } return s diff --git a/vendor/src/github.com/docker/libnetwork/ipamapi/contract.go b/vendor/src/github.com/docker/libnetwork/ipamapi/contract.go index 5323c4f7df..5d561d81df 100644 --- a/vendor/src/github.com/docker/libnetwork/ipamapi/contract.go +++ b/vendor/src/github.com/docker/libnetwork/ipamapi/contract.go @@ -22,8 +22,10 @@ const ( // Callback provides a Callback interface for registering an IPAM instance into LibNetwork type Callback interface { - // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a ipam instance + // RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork RegisterIpamDriver(name string, driver Ipam) error + // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify cpaabilities + RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error } /************** @@ -70,3 +72,8 @@ type Ipam interface { // Release the address from the specified pool ID ReleaseAddress(string, net.IP) error } + +// Capability represents the requirements and capabilities of the IPAM driver +type Capability struct { + RequiresMACAddress bool +} diff --git a/vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go b/vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go index b8d21fdc6b..e357630cbb 100644 --- a/vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go +++ b/vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go @@ -2,6 +2,8 @@ // messages between libnetwork and the remote ipam plugin package api +import "github.com/docker/libnetwork/ipamapi" + // Response is the basic response structure used in all responses type Response struct { Error string @@ -17,6 +19,17 @@ func (r *Response) GetError() string { return r.Error } +// GetCapabilityResponse is the response of GetCapability request +type GetCapabilityResponse struct { + Response + RequiresMACAddress bool +} + +// ToCapability converts the capability response into the internal ipam driver capaility structure +func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability { + return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress} +} + // GetAddressSpacesResponse is the response to the ``get default address spaces`` request message type GetAddressSpacesResponse struct { Response diff --git a/vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go b/vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go index 3aefd430ab..581a9c8871 100644 --- a/vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go +++ b/vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go @@ -30,8 +30,17 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam { // Init registers a remote ipam when its plugin is activated func Init(cb ipamapi.Callback, l, g interface{}) error { plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) { - if err := cb.RegisterIpamDriver(name, newAllocator(name, client)); err != nil { - log.Errorf("error registering remote ipam %s due to %v", name, err) + a := newAllocator(name, client) + if cps, err := a.(*allocator).getCapabilities(); err == nil { + if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil { + log.Errorf("error registering remote ipam driver %s due to %v", name, err) + } + } else { + log.Infof("remote ipam driver %s does not support capabilities", name) + log.Debug(err) + if err := cb.RegisterIpamDriver(name, a); err != nil { + log.Errorf("error registering remote ipam driver %s due to %v", name, err) + } } }) return nil @@ -49,6 +58,14 @@ func (a *allocator) call(methodName string, arg interface{}, retVal PluginRespon return nil } +func (a *allocator) getCapabilities() (*ipamapi.Capability, error) { + var res api.GetCapabilityResponse + if err := a.call("GetCapabilities", nil, &res); err != nil { + return nil, err + } + return res.ToCapability(), nil +} + // GetDefaultAddressSpaces returns the local and global default address spaces func (a *allocator) GetDefaultAddressSpaces() (string, string, error) { res := &api.GetAddressSpacesResponse{} diff --git a/vendor/src/github.com/docker/libnetwork/ipamutils/utils_freebsd.go b/vendor/src/github.com/docker/libnetwork/ipamutils/utils_freebsd.go new file mode 100644 index 0000000000..09eced12d1 --- /dev/null +++ b/vendor/src/github.com/docker/libnetwork/ipamutils/utils_freebsd.go @@ -0,0 +1,22 @@ +// Package ipamutils provides utililty functions for ipam management +package ipamutils + +import ( + "net" + + "github.com/docker/libnetwork/types" +) + +// ElectInterfaceAddresses looks for an interface on the OS with the specified name +// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, +// it chooses from a predifined list the first IPv4 address which does not conflict +// with other interfaces on the system. +func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) { + return nil, nil, types.NotImplementedErrorf("not supported on freebsd") +} + +// FindAvailableNetwork returns a network from the passed list which does not +// overlap with existing interfaces in the system +func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) { + return nil, types.NotImplementedErrorf("not supported on freebsd") +} diff --git a/vendor/src/github.com/docker/libnetwork/netlabel/labels.go b/vendor/src/github.com/docker/libnetwork/netlabel/labels.go index cb0c2f5402..c6d7f13477 100644 --- a/vendor/src/github.com/docker/libnetwork/netlabel/labels.go +++ b/vendor/src/github.com/docker/libnetwork/netlabel/labels.go @@ -41,6 +41,9 @@ const ( // Gateway represents the gateway for the network Gateway = Prefix + ".gateway" + + // Internal constant represents that the network is internal which disables default gateway service + Internal = Prefix + ".internal" ) var ( diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index be4ab70505..f18c91a19b 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -16,6 +16,7 @@ import ( "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/types" ) @@ -58,6 +59,7 @@ type Network interface { // NetworkInfo returns some configuration and operational information about the network type NetworkInfo interface { IpamConfig() (string, []*IpamConf, []*IpamConf) + IpamInfo() ([]*IpamInfo, []*IpamInfo) DriverOptions() map[string]string Scope() string } @@ -161,6 +163,7 @@ type network struct { persist bool stopWatchCh chan struct{} drvOnce *sync.Once + internal bool sync.Mutex } @@ -303,6 +306,7 @@ func (n *network) CopyTo(o datastore.KVObject) error { dstN.dbIndex = n.dbIndex dstN.dbExists = n.dbExists dstN.drvOnce = n.drvOnce + dstN.internal = n.internal for _, v4conf := range n.ipamV4Config { dstV4Conf := &IpamConf{} @@ -389,6 +393,7 @@ func (n *network) MarshalJSON() ([]byte, error) { } netMap["ipamV6Info"] = string(iis) } + netMap["internal"] = n.internal return json.Marshal(netMap) } @@ -452,6 +457,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { return err } } + if v, ok := netMap["internal"]; ok { + n.internal = v.(bool) + } return nil } @@ -478,6 +486,18 @@ func NetworkOptionPersist(persist bool) NetworkOption { } } +// NetworkOptionInternalNetwork returns an option setter to config the network +// to be internal which disables default gateway service +func NetworkOptionInternalNetwork() NetworkOption { + return func(n *network) { + n.internal = true + if n.generic == nil { + n.generic = make(map[string]interface{}) + } + n.generic[netlabel.Internal] = true + } +} + // NetworkOptionIpam function returns an option setter for the ipam configuration for this network func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption { return func(n *network) { @@ -678,7 +698,22 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi } } - if err = ep.assignAddress(true, !n.postIPv6); err != nil { + ipam, err := n.getController().getIPAM(n.ipamType) + if err != nil { + return nil, err + } + + if ipam.capability.RequiresMACAddress { + if ep.iface.mac == nil { + ep.iface.mac = netutils.GenerateRandomMAC() + } + if ep.ipamOptions == nil { + ep.ipamOptions = make(map[string]string) + } + ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String() + } + + if err = ep.assignAddress(ipam.driver, true, !n.postIPv6); err != nil { return nil, err } defer func() { @@ -698,7 +733,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi } }() - if err = ep.assignAddress(false, n.postIPv6); err != nil { + if err = ep.assignAddress(ipam.driver, false, n.postIPv6); err != nil { return nil, err } @@ -1148,3 +1183,32 @@ func (n *network) IpamConfig() (string, []*IpamConf, []*IpamConf) { return n.ipamType, v4L, v6L } + +func (n *network) IpamInfo() ([]*IpamInfo, []*IpamInfo) { + n.Lock() + defer n.Unlock() + + v4Info := make([]*IpamInfo, len(n.ipamV4Info)) + v6Info := make([]*IpamInfo, len(n.ipamV6Info)) + + for i, info := range n.ipamV4Info { + ic := &IpamInfo{} + info.CopyTo(ic) + v4Info[i] = ic + } + + for i, info := range n.ipamV6Info { + ic := &IpamInfo{} + info.CopyTo(ic) + v6Info[i] = ic + } + + return v4Info, v6Info +} + +func (n *network) Internal() bool { + n.Lock() + defer n.Unlock() + + return n.internal +} diff --git a/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go index d57e7601b1..720bf09764 100644 --- a/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go @@ -109,6 +109,7 @@ func (i *nwIface) Remove() error { n.Lock() path := n.path + isDefault := n.isDefault n.Unlock() return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error { @@ -134,7 +135,7 @@ func (i *nwIface) Remove() error { if err := netlink.LinkDel(iface); err != nil { return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err) } - } else { + } else if !isDefault { // Move the network interface to caller namespace. if err := netlink.LinkSetNsFd(iface, callerFD); err != nil { fmt.Println("LinkSetNsPid failed: ", err) @@ -213,9 +214,15 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If } n.Lock() - i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex) - n.nextIfIndex++ + if n.isDefault { + i.dstName = i.srcName + } else { + i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex) + n.nextIfIndex++ + } + path := n.path + isDefault := n.isDefault n.Unlock() return nsInvoke(path, func(nsFD int) error { @@ -231,9 +238,13 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err) } - // Move the network interface to the destination namespace. - if err := netlink.LinkSetNsFd(iface, nsFD); err != nil { - return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err) + // Move the network interface to the destination + // namespace only if the namespace is not a default + // type + if !isDefault { + if err := netlink.LinkSetNsFd(iface, nsFD); err != nil { + return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err) + } } return nil diff --git a/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go index 1b7b230380..07b725c290 100644 --- a/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go @@ -41,6 +41,7 @@ type networkNamespace struct { staticRoutes []*types.StaticRoute neighbors []*neigh nextIfIndex int + isDefault bool sync.Mutex } @@ -146,7 +147,7 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) { return nil, err } - return &networkNamespace{path: key}, nil + return &networkNamespace{path: key, isDefault: !osCreate}, nil } func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter { diff --git a/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go b/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go index 36bd6c8002..7c6dcacead 100644 --- a/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go +++ b/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go @@ -19,6 +19,11 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) { return nil, nil } +// GetSandboxForExternalKey returns sandbox object for the supplied path +func GetSandboxForExternalKey(path string, key string) (Sandbox, error) { + return nil, nil +} + // GC triggers garbage collection of namespace path right away // and waits for it. func GC() {