diff --git a/libnetwork/controller.go b/libnetwork/controller.go index d11ffda526..35f945ecb6 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -92,6 +92,12 @@ type NetworkController interface { // When the function returns true, the walk will stop. type NetworkWalker func(nw Network) bool +type driverData struct { + driver driverapi.Driver + capability driverapi.Capability +} + +type driverTable map[string]*driverData type networkTable map[types.UUID]*network type endpointTable map[types.UUID]*endpoint type sandboxTable map[string]*sandboxData @@ -175,21 +181,21 @@ func (c *controller) hostLeaveCallback(hosts []net.IP) { func (c *controller) ConfigureNetworkDriver(networkType string, options map[string]interface{}) error { c.Lock() - d, ok := c.drivers[networkType] + dd, ok := c.drivers[networkType] c.Unlock() if !ok { return NetworkTypeError(networkType) } - return d.Config(options) + return dd.driver.Config(options) } -func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) error { +func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error { c.Lock() defer c.Unlock() if _, ok := c.drivers[networkType]; ok { return driverapi.ErrActiveRegistration(networkType) } - c.drivers[networkType] = driver + c.drivers[networkType] = &driverData{driver, capability} return nil } @@ -238,18 +244,21 @@ func (c *controller) addNetwork(n *network) error { c.Lock() // Check if a driver for the specified network type is available - d, ok := c.drivers[n.networkType] + dd, ok := c.drivers[n.networkType] c.Unlock() if !ok { var err error - d, err = c.loadDriver(n.networkType) + dd, err = c.loadDriver(n.networkType) if err != nil { return err } } - n.driver = d + n.Lock() + n.driver = dd.driver + d := n.driver + n.Unlock() // Create the network if err := d.CreateNetwork(n.id, n.generic); err != nil { @@ -317,7 +326,7 @@ func (c *controller) NetworkByID(id string) (Network, error) { return nil, ErrNoSuchNetwork(id) } -func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { +func (c *controller) loadDriver(networkType string) (*driverData, error) { // Plugins pkg performs lazy loading of plugins that acts as remote drivers. // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. _, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) @@ -329,11 +338,24 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { } c.Lock() defer c.Unlock() - d, ok := c.drivers[networkType] + dd, ok := c.drivers[networkType] if !ok { return nil, ErrInvalidNetworkDriver(networkType) } - return d, nil + return dd, nil +} + +func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) { + c.Lock() + dd, ok := c.drivers[networkType] + c.Unlock() + if !ok { + return false, types.NotFoundErrorf("driver not found for %s", networkType) + } + if dd.capability.Scope == driverapi.GlobalScope { + return true, nil + } + return false, nil } func (c *controller) GC() { diff --git a/libnetwork/driverapi/driverapi.go b/libnetwork/driverapi/driverapi.go index 45c136dc45..e53947d82e 100644 --- a/libnetwork/driverapi/driverapi.go +++ b/libnetwork/driverapi/driverapi.go @@ -118,5 +118,20 @@ type JoinInfo interface { // DriverCallback provides a Callback interface for Drivers into LibNetwork type DriverCallback interface { // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance - RegisterDriver(name string, driver Driver) error + RegisterDriver(name string, driver Driver, capability Capability) error +} + +// Scope indicates the drivers scope capability +type Scope int + +const ( + // LocalScope represents the driver capable of providing networking services for containers in a single host + LocalScope Scope = iota + // GlobalScope represents the driver capable of providing networking services for containers across hosts + GlobalScope +) + +// Capability represents the high level capabilities of the drivers which libnetwork can make use of +type Capability struct { + Scope Scope } diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index ce58ddb2ef..33326e7d2a 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -110,7 +110,10 @@ func Init(dc driverapi.DriverCallback) error { if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil { logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err) } - return dc.RegisterDriver(networkType, newDriver()) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, newDriver(), c) } // Validate performs a static validation on the network configuration parameters. diff --git a/libnetwork/drivers/host/host.go b/libnetwork/drivers/host/host.go index 8698766ee6..072cc890ab 100644 --- a/libnetwork/drivers/host/host.go +++ b/libnetwork/drivers/host/host.go @@ -16,7 +16,10 @@ type driver struct { // Init registers a new instance of host driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/libnetwork/drivers/null/null.go b/libnetwork/drivers/null/null.go index 26f9d00fe1..d1f2797e5d 100644 --- a/libnetwork/drivers/null/null.go +++ b/libnetwork/drivers/null/null.go @@ -16,7 +16,10 @@ type driver struct { // Init registers a new instance of null driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/libnetwork/drivers/remote/driver.go b/libnetwork/drivers/remote/driver.go index 858064cb54..1395933a17 100644 --- a/libnetwork/drivers/remote/driver.go +++ b/libnetwork/drivers/remote/driver.go @@ -23,7 +23,10 @@ func newDriver(name string, client *plugins.Client) driverapi.Driver { // plugin is activated. func Init(dc driverapi.DriverCallback) error { plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { - if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil { + c := driverapi.Capability{ + Scope: driverapi.GlobalScope, + } + if err := dc.RegisterDriver(name, newDriver(name, client), c); err != nil { log.Errorf("error registering driver for %s due to %v", name, err) } }) diff --git a/libnetwork/drivers/windows/windows.go b/libnetwork/drivers/windows/windows.go index 8606a6f4e5..925e402bb0 100644 --- a/libnetwork/drivers/windows/windows.go +++ b/libnetwork/drivers/windows/windows.go @@ -13,7 +13,10 @@ type driver struct{} // Init registers a new instance of null driver func Init(dc driverapi.DriverCallback) error { - return dc.RegisterDriver(networkType, &driver{}) + c := driverapi.Capability{ + Scope: driverapi.LocalScope, + } + return dc.RegisterDriver(networkType, &driver{}, c) } func (d *driver) Config(option map[string]interface{}) error { diff --git a/libnetwork/drivers_freebsd.go b/libnetwork/drivers_freebsd.go index c693d7c472..683af06ce9 100644 --- a/libnetwork/drivers_freebsd.go +++ b/libnetwork/drivers_freebsd.go @@ -6,8 +6,6 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ null.Init, diff --git a/libnetwork/drivers_linux.go b/libnetwork/drivers_linux.go index 130f7ab343..7de28f95eb 100644 --- a/libnetwork/drivers_linux.go +++ b/libnetwork/drivers_linux.go @@ -8,8 +8,6 @@ import ( "github.com/docker/libnetwork/drivers/remote" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ bridge.Init, diff --git a/libnetwork/drivers_windows.go b/libnetwork/drivers_windows.go index b1ab31e84f..334cd7c9fe 100644 --- a/libnetwork/drivers_windows.go +++ b/libnetwork/drivers_windows.go @@ -5,8 +5,6 @@ import ( "github.com/docker/libnetwork/drivers/windows" ) -type driverTable map[string]driverapi.Driver - func initDrivers(dc driverapi.DriverCallback) error { for _, fn := range [](func(driverapi.DriverCallback) error){ windows.Init, diff --git a/libnetwork/libnetwork_internal_test.go b/libnetwork/libnetwork_internal_test.go index 3778921cf6..23a0a54fc7 100644 --- a/libnetwork/libnetwork_internal_test.go +++ b/libnetwork/libnetwork_internal_test.go @@ -13,14 +13,14 @@ func TestDriverRegistration(t *testing.T) { if err != nil { t.Fatal(err) } - err = c.(*controller).RegisterDriver(bridgeNetType, nil) + err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{}) if err == nil { t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType) } if _, ok := err.(driverapi.ErrActiveRegistration); !ok { t.Fatalf("Failed for unexpected reason: %v", err) } - err = c.(*controller).RegisterDriver("test-dummy", nil) + err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{}) if err != nil { t.Fatalf("Test failed with an error %v", err) } diff --git a/libnetwork/network.go b/libnetwork/network.go index 88398f8d82..8f3e79906a 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -2,7 +2,6 @@ package libnetwork import ( "encoding/json" - "strings" "sync" log "github.com/Sirupsen/logrus" @@ -377,12 +376,9 @@ func (n *network) EndpointByID(id string) (Endpoint, error) { return nil, ErrNoSuchEndpoint(id) } -func isReservedNetwork(name string) bool { - reserved := []string{"bridge", "none", "host"} - for _, r := range reserved { - if strings.EqualFold(r, name) { - return true - } - } - return false +func (n *network) isGlobalScoped() (bool, error) { + n.Lock() + c := n.ctrlr + n.Unlock() + return c.isDriverGlobalScoped(n.networkType) } diff --git a/libnetwork/store.go b/libnetwork/store.go index a7c47c833c..c72d739715 100644 --- a/libnetwork/store.go +++ b/libnetwork/store.go @@ -37,8 +37,9 @@ func (c *controller) newNetworkFromStore(n *network) error { } func (c *controller) updateNetworkToStore(n *network) error { - if isReservedNetwork(n.Name()) { - return nil + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } c.Lock() cs := c.store @@ -52,8 +53,9 @@ func (c *controller) updateNetworkToStore(n *network) error { } func (c *controller) deleteNetworkFromStore(n *network) error { - if isReservedNetwork(n.Name()) { - return nil + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } c.Lock() cs := c.store @@ -111,12 +113,13 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error { func (c *controller) updateEndpointToStore(ep *endpoint) error { ep.Lock() + n := ep.network name := ep.name - if isReservedNetwork(ep.network.name) { - ep.Unlock() - return nil - } ep.Unlock() + global, err := n.isGlobalScoped() + if err != nil || !global { + return err + } c.Lock() cs := c.store c.Unlock() @@ -137,9 +140,14 @@ func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) { } func (c *controller) deleteEndpointFromStore(ep *endpoint) error { - if isReservedNetwork(ep.network.Name()) { - return nil + ep.Lock() + n := ep.network + ep.Unlock() + global, err := n.isGlobalScoped() + if err != nil || !global { + return err } + c.Lock() cs := c.store c.Unlock()