libnetwork vendoring

Vendoring libnetwork @ 9f0563ea8f430d8828553aac97161cbff4056436

Brings in:
    * Support for overlay network driver in 3.10+ kernels
    * Freebsd compilation fixes
    * Remove .dockerinit dependency
    * IPAM driver capability support
    * Network internal mode support
    * Misc. fixes

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-12-18 11:03:57 -08:00
parent 312c82677b
commit f0904affd1
23 changed files with 486 additions and 81 deletions

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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
}

View file

@ -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

View file

@ -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)
}

View file

@ -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{

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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,
}

View file

@ -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),
}

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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{}

View file

@ -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")
}

View file

@ -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 (

View file

@ -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
}

View file

@ -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

View file

@ -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 {

View file

@ -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() {