1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Added driver specific config support

- Added api enhancement to pass driver specific config
  - Refactored simple bridge driver code for driver specific config
  - Added an undocumented option to add non-default bridges without
    manual pre-provisioning to help libnetwork testing
  - Reenabled libnetwork test to do api testing
  - Updated README.md

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-04-15 05:25:42 +00:00
parent b4481f4d50
commit e797f80ad4
28 changed files with 333 additions and 254 deletions

View file

@ -23,9 +23,17 @@ There are many networking solutions available to suit a broad range of use-cases
// Create a new controller instance
controller := libnetwork.New()
options := options.Generic{}
// This option is only needed for in-tree drivers. Plugins(in future) will get
// their options through plugin infrastructure.
option := options.Generic{}
driver, err := controller.NewNetworkDriver("simplebridge", option)
if err != nil {
return
}
netOptions := options.Generic{}
// Create a network for containers to join.
network, err := controller.NewNetwork("simplebridge", "network1", options)
network, err := controller.NewNetwork(driver, "network1", netOptions)
if err != nil {
return
}

View file

@ -15,7 +15,8 @@ func main() {
options := options.Generic{"AddressIPv4": net}
controller := libnetwork.New()
netw, err := controller.NewNetwork("simplebridge", "dummy", options)
driver, _ := controller.NewNetworkDriver("simplebridge", options)
netw, err := controller.NewNetwork(driver, "dummy", "")
if err != nil {
log.Fatal(err)
}

View file

@ -19,8 +19,11 @@ type UUID string
// Driver is an interface that every plugin driver needs to implement.
type Driver interface {
// Push driver specific config to the driver
Config(config interface{}) error
// CreateNetwork invokes the driver method to create a network passing
// the network id and driver specific config. The config mechanism will
// the network id and network specific config. The config mechanism will
// eventually be replaced with labels which are yet to be introduced.
CreateNetwork(nid UUID, config interface{}) error

View file

@ -8,7 +8,8 @@ import (
type driverTable map[string]driverapi.Driver
func enumerateDrivers() driverTable {
var drivers driverTable
drivers := make(driverTable)
for _, fn := range [](func() (string, driverapi.Driver)){bridge.New} {
name, driver := fn()
drivers[name] = driver

View file

@ -45,6 +45,7 @@ type Configuration struct {
EnableIPMasquerade bool
EnableICC bool
EnableIPForwarding bool
AllowNonDefaultBridge bool
}
type bridgeEndpoint struct {
@ -62,6 +63,7 @@ type bridgeNetwork struct {
}
type driver struct {
config *Configuration
network *bridgeNetwork
sync.Mutex
}
@ -76,15 +78,45 @@ func New() (string, driverapi.Driver) {
return networkType, &driver{}
}
func (d *driver) Config(option interface{}) error {
var config *Configuration
d.Lock()
defer d.Unlock()
if d.config != nil {
return fmt.Errorf("configuration already exists, simplebridge configuration can be applied only once")
}
switch opt := option.(type) {
case options.Generic:
opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
if err != nil {
return fmt.Errorf("failed to generate driver config: %v", err)
}
config = opaqueConfig.(*Configuration)
case *Configuration:
config = opt
}
d.config = config
return nil
}
// Create a new network using simplebridge plugin
func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error {
var (
config *Configuration
err error
)
d.Lock()
if d.config == nil {
d.Unlock()
return fmt.Errorf("trying to create a network on a driver without valid config")
}
config := d.config
if d.network != nil {
d.Unlock()
return fmt.Errorf("network already exists, simplebridge can only have one network")
@ -100,19 +132,8 @@ func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error {
}
}()
switch opt := option.(type) {
case options.Generic:
opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
if err != nil {
return fmt.Errorf("failed to generate driver config: %v", err)
}
config = opaqueConfig.(*Configuration)
case *Configuration:
config = opt
}
bridgeIface := newInterface(config)
bridgeSetup := newBridgeSetup(bridgeIface)
bridgeSetup := newBridgeSetup(config, bridgeIface)
// If the bridge interface doesn't exist, we need to start the setup steps
// by creating a new device and assigning it an IPv4 address.
@ -199,7 +220,7 @@ func (d *driver) DeleteNetwork(nid driverapi.UUID) error {
return err
}
func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config interface{}) (*driverapi.SandboxInfo, error) {
func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOption interface{}) (*driverapi.SandboxInfo, error) {
var (
ipv6Addr net.IPNet
err error
@ -207,6 +228,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
d.Lock()
n := d.network
config := d.config
d.Unlock()
if n == nil {
return nil, driverapi.ErrNoNetwork
@ -271,7 +293,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
}()
if err = netlink.LinkSetMaster(host,
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: n.bridge.Config.BridgeName}}); err != nil {
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
return nil, err
}
@ -281,7 +303,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
}
ipv4Addr := net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
if n.bridge.Config.EnableIPv6 {
if config.EnableIPv6 {
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
if err != nil {
return nil, err
@ -297,7 +319,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
intf.DstName = containerVeth
intf.Address = ipv4Addr
sinfo.Gateway = n.bridge.bridgeIPv4.IP
if n.bridge.Config.EnableIPv6 {
if config.EnableIPv6 {
intf.AddressIPv6 = ipv6Addr
sinfo.GatewayIPv6 = n.bridge.bridgeIPv6.IP
}
@ -314,6 +336,7 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error {
d.Lock()
n := d.network
config := d.config
d.Unlock()
if n == nil {
return driverapi.ErrNoNetwork
@ -356,8 +379,8 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error {
return err
}
if n.bridge.Config.EnableIPv6 {
err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, n.endpoint.addressIPv6)
if config.EnableIPv6 {
err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, ep.addressIPv6)
if err != nil {
return err
}

View file

@ -12,8 +12,11 @@ func TestCreate(t *testing.T) {
_, d := New()
config := &Configuration{BridgeName: DefaultBridgeName}
err := d.CreateNetwork("dummy", config)
if err != nil {
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
if err := d.CreateNetwork("dummy", ""); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
}
@ -23,7 +26,11 @@ func TestCreateFail(t *testing.T) {
_, d := New()
config := &Configuration{BridgeName: "dummy0"}
if err := d.CreateNetwork("dummy", config); err == nil {
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
if err := d.CreateNetwork("dummy", ""); err == nil {
t.Fatal("Bridge creation was expected to fail")
}
}
@ -40,8 +47,11 @@ func TestCreateFullOptions(t *testing.T) {
EnableIPForwarding: true,
}
_, config.FixedCIDRv6, _ = net.ParseCIDR("2001:db8::/48")
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
err := d.CreateNetwork("dummy", config)
err := d.CreateNetwork("dummy", "")
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}

View file

@ -14,7 +14,6 @@ const (
// Interface models the bridge network device.
type bridgeInterface struct {
Config *Configuration
Link netlink.Link
bridgeIPv4 *net.IPNet
bridgeIPv6 *net.IPNet
@ -25,17 +24,15 @@ type bridgeInterface struct {
// or the default bridge name when unspecified), but doesn't attempt to create
// on when missing
func newInterface(config *Configuration) *bridgeInterface {
i := &bridgeInterface{
Config: config,
}
i := &bridgeInterface{}
// Initialize the bridge name to the default if unspecified.
if i.Config.BridgeName == "" {
i.Config.BridgeName = DefaultBridgeName
if config.BridgeName == "" {
config.BridgeName = DefaultBridgeName
}
// Attempt to find an existing bridge named with the specified name.
i.Link, _ = netlink.LinkByName(i.Config.BridgeName)
i.Link, _ = netlink.LinkByName(config.BridgeName)
return i
}

View file

@ -10,8 +10,9 @@ import (
func TestInterfaceDefaultName(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
if inf := newInterface(&Configuration{}); inf.Config.BridgeName != DefaultBridgeName {
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, inf.Config.BridgeName)
config := &Configuration{}
if _ = newInterface(config); config.BridgeName != DefaultBridgeName {
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
}
}

View file

@ -16,7 +16,11 @@ func TestLinkCreate(t *testing.T) {
config := &Configuration{
BridgeName: DefaultBridgeName,
EnableIPv6: true}
err := d.CreateNetwork("dummy", config)
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
err := d.CreateNetwork("dummy", "")
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -69,7 +73,11 @@ func TestLinkCreateTwo(t *testing.T) {
config := &Configuration{
BridgeName: DefaultBridgeName,
EnableIPv6: true}
err := d.CreateNetwork("dummy", config)
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
err := d.CreateNetwork("dummy", "")
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -95,7 +103,11 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
config := &Configuration{
BridgeName: DefaultBridgeName}
err := d.CreateNetwork("dummy", config)
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
err := d.CreateNetwork("dummy", "")
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}

View file

@ -1,19 +1,20 @@
package bridge
type setupStep func(*bridgeInterface) error
type setupStep func(*Configuration, *bridgeInterface) error
type bridgeSetup struct {
config *Configuration
bridge *bridgeInterface
steps []setupStep
}
func newBridgeSetup(i *bridgeInterface) *bridgeSetup {
return &bridgeSetup{bridge: i}
func newBridgeSetup(c *Configuration, i *bridgeInterface) *bridgeSetup {
return &bridgeSetup{config: c, bridge: i}
}
func (b *bridgeSetup) apply() error {
for _, fn := range b.steps {
if err := fn(b.bridge); err != nil {
if err := fn(b.config, b.bridge); err != nil {
return err
}
}

View file

@ -10,17 +10,17 @@ import (
)
// SetupDevice create a new bridge interface/
func setupDevice(i *bridgeInterface) error {
func setupDevice(config *Configuration, i *bridgeInterface) error {
// We only attempt to create the bridge when the requested device name is
// the default one.
if i.Config.BridgeName != DefaultBridgeName {
return fmt.Errorf("bridge device with non default name %q must be created manually", i.Config.BridgeName)
if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
return fmt.Errorf("bridge device with non default name %q must be created manually", config.BridgeName)
}
// Set the bridgeInterface netlink.Bridge.
i.Link = &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: i.Config.BridgeName,
Name: config.BridgeName,
},
}
@ -37,7 +37,7 @@ func setupDevice(i *bridgeInterface) error {
}
// SetupDeviceUp ups the given bridge interface.
func setupDeviceUp(i *bridgeInterface) error {
func setupDeviceUp(config *Configuration, i *bridgeInterface) error {
err := netlink.LinkSetUp(i.Link)
if err != nil {
return err
@ -45,7 +45,7 @@ func setupDeviceUp(i *bridgeInterface) error {
// Attempt to update the bridge interface to refresh the flags status,
// ignoring any failure to do so.
if lnk, err := netlink.LinkByName(i.Config.BridgeName); err == nil {
if lnk, err := netlink.LinkByName(config.BridgeName); err == nil {
i.Link = lnk
}
return nil

View file

@ -13,12 +13,10 @@ import (
func TestSetupNewBridge(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := &bridgeInterface{
Config: &Configuration{
BridgeName: DefaultBridgeName,
},
}
if err := setupDevice(br); err != nil {
config := &Configuration{BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
if br.Link == nil {
@ -35,12 +33,10 @@ func TestSetupNewBridge(t *testing.T) {
func TestSetupNewNonDefaultBridge(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := &bridgeInterface{
Config: &Configuration{
BridgeName: "test0",
},
}
if err := setupDevice(br); err == nil || !strings.Contains(err.Error(), "non default name") {
config := &Configuration{BridgeName: "test0"}
br := &bridgeInterface{}
if err := setupDevice(config, br); err == nil || !strings.Contains(err.Error(), "non default name") {
t.Fatalf("Expected bridge creation failure with \"non default name\", got: %v", err)
}
}
@ -48,15 +44,13 @@ func TestSetupNewNonDefaultBridge(t *testing.T) {
func TestSetupDeviceUp(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := &bridgeInterface{
Config: &Configuration{
BridgeName: DefaultBridgeName,
},
}
if err := setupDevice(br); err != nil {
config := &Configuration{BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
if err := setupDeviceUp(br); err != nil {
if err := setupDeviceUp(config, br); err != nil {
t.Fatalf("Failed to up bridge device: %v", err)
}

View file

@ -6,15 +6,15 @@ import (
log "github.com/Sirupsen/logrus"
)
func setupFixedCIDRv4(i *bridgeInterface) error {
func setupFixedCIDRv4(config *Configuration, i *bridgeInterface) error {
addrv4, _, err := i.addresses()
if err != nil {
return err
}
log.Debugf("Using IPv4 subnet: %v", i.Config.FixedCIDR)
if err := ipAllocator.RegisterSubnet(addrv4.IPNet, i.Config.FixedCIDR); err != nil {
return fmt.Errorf("Setup FixedCIDRv4 failed for subnet %s in %s: %v", i.Config.FixedCIDR, addrv4.IPNet, err)
log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
return fmt.Errorf("Setup FixedCIDRv4 failed for subnet %s in %s: %v", config.FixedCIDR, addrv4.IPNet, err)
}
return nil

View file

@ -10,25 +10,24 @@ import (
func TestSetupFixedCIDRv4(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := &bridgeInterface{
Config: &Configuration{
config := &Configuration{
BridgeName: DefaultBridgeName,
AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(16, 32)},
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
},
}
if err := setupDevice(br); err != nil {
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}}
br := &bridgeInterface{}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
if err := setupBridgeIPv4(br); err != nil {
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
}
if err := setupFixedCIDRv4(br); err != nil {
if err := setupFixedCIDRv4(config, br); err != nil {
t.Fatalf("Failed to setup bridge FixedCIDRv4: %v", err)
}
if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDR, nil); err != nil {
if ip, err := ipAllocator.RequestIP(config.FixedCIDR, nil); err != nil {
t.Fatalf("Failed to request IP to allocator: %v", err)
} else if expected := "192.168.2.1"; ip.String() != expected {
t.Fatalf("Expected allocated IP %s, got %s", expected, ip)
@ -38,21 +37,20 @@ func TestSetupFixedCIDRv4(t *testing.T) {
func TestSetupBadFixedCIDRv4(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := &bridgeInterface{
Config: &Configuration{
config := &Configuration{
BridgeName: DefaultBridgeName,
AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(24, 32)},
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
},
}
if err := setupDevice(br); err != nil {
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)}}
br := &bridgeInterface{}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
if err := setupBridgeIPv4(br); err != nil {
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
}
if err := setupFixedCIDRv4(br); err == nil {
if err := setupFixedCIDRv4(config, br); err == nil {
t.Fatal("Setup bridge FixedCIDRv4 should have failed")
}
}

View file

@ -6,10 +6,10 @@ import (
log "github.com/Sirupsen/logrus"
)
func setupFixedCIDRv6(i *bridgeInterface) error {
log.Debugf("Using IPv6 subnet: %v", i.Config.FixedCIDRv6)
if err := ipAllocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6); err != nil {
return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", i.Config.FixedCIDRv6, i.Config.FixedCIDRv6, err)
func setupFixedCIDRv6(config *Configuration, i *bridgeInterface) error {
log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", config.FixedCIDRv6, config.FixedCIDRv6, err)
}
return nil

View file

@ -10,25 +10,26 @@ import (
func TestSetupFixedCIDRv6(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := newInterface(&Configuration{})
config := &Configuration{}
br := newInterface(config)
_, br.Config.FixedCIDRv6, _ = net.ParseCIDR("2002:db8::/48")
if err := setupDevice(br); err != nil {
_, config.FixedCIDRv6, _ = net.ParseCIDR("2002:db8::/48")
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
if err := setupBridgeIPv4(br); err != nil {
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
}
if err := setupBridgeIPv6(br); err != nil {
if err := setupBridgeIPv6(config, br); err != nil {
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
}
if err := setupFixedCIDRv6(br); err != nil {
if err := setupFixedCIDRv6(config, br); err != nil {
t.Fatalf("Failed to setup bridge FixedCIDRv6: %v", err)
}
if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDRv6, nil); err != nil {
if ip, err := ipAllocator.RequestIP(config.FixedCIDRv6, nil); err != nil {
t.Fatalf("Failed to request IP to allocator: %v", err)
} else if expected := "2002:db8::1"; ip.String() != expected {
t.Fatalf("Expected allocated IP %s, got %s", expected, ip)

View file

@ -10,9 +10,9 @@ const (
ipv4ForwardConfPerm = 0644
)
func setupIPForwarding(i *bridgeInterface) error {
func setupIPForwarding(config *Configuration, i *bridgeInterface) error {
// Sanity Check
if i.Config.EnableIPForwarding == false {
if config.EnableIPForwarding == false {
return fmt.Errorf("Unexpected request to enable IP Forwarding for: %v", *i)
}

View file

@ -18,15 +18,13 @@ func TestSetupIPForwarding(t *testing.T) {
}
// Create test interface with ip forwarding setting enabled
br := &bridgeInterface{
Config: &Configuration{
config := &Configuration{
BridgeName: DefaultBridgeName,
EnableIPForwarding: true,
},
}
EnableIPForwarding: true}
br := &bridgeInterface{}
// Set IP Forwarding
if err := setupIPForwarding(br); err != nil {
if err := setupIPForwarding(config, br); err != nil {
t.Fatalf("Failed to setup IP forwarding: %v", err)
}
@ -43,15 +41,13 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
defer reconcileIPForwardingSetting(t, procSetting)
// Create test interface without ip forwarding setting enabled
br := &bridgeInterface{
Config: &Configuration{
config := &Configuration{
BridgeName: DefaultBridgeName,
EnableIPForwarding: false,
},
}
EnableIPForwarding: false}
br := &bridgeInterface{}
// Attempt Set IP Forwarding
if err := setupIPForwarding(br); err == nil {
if err := setupIPForwarding(config, br); err == nil {
t.Fatal("Setup IP forwarding was expected to fail")
} else if !strings.Contains(err.Error(), "Unexpected request") {
t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)

View file

@ -13,26 +13,26 @@ const (
DockerChain = "DOCKER"
)
func setupIPTables(i *bridgeInterface) error {
func setupIPTables(config *Configuration, i *bridgeInterface) error {
// Sanity check.
if i.Config.EnableIPTables == false {
return fmt.Errorf("Unexpected request to set IP tables for interface: %s", i.Config.BridgeName)
if config.EnableIPTables == false {
return fmt.Errorf("Unexpected request to set IP tables for interface: %s", config.BridgeName)
}
addrv4, _, err := netutils.GetIfaceAddr(i.Config.BridgeName)
addrv4, _, err := netutils.GetIfaceAddr(config.BridgeName)
if err != nil {
return fmt.Errorf("Failed to setup IP tables, cannot acquire Interface address: %s", err.Error())
}
if err = setupIPTablesInternal(i.Config.BridgeName, addrv4, i.Config.EnableICC, i.Config.EnableIPMasquerade, true); err != nil {
if err = setupIPTablesInternal(config.BridgeName, addrv4, config.EnableICC, config.EnableIPMasquerade, true); err != nil {
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
}
_, err = iptables.NewChain(DockerChain, i.Config.BridgeName, iptables.Nat)
_, err = iptables.NewChain(DockerChain, config.BridgeName, iptables.Nat)
if err != nil {
return fmt.Errorf("Failed to create NAT chain: %s", err.Error())
}
chain, err := iptables.NewChain(DockerChain, i.Config.BridgeName, iptables.Filter)
chain, err := iptables.NewChain(DockerChain, config.BridgeName, iptables.Filter)
if err != nil {
return fmt.Errorf("Failed to create FILTER chain: %s", err.Error())
}

View file

@ -15,7 +15,7 @@ const (
func TestProgramIPTable(t *testing.T) {
// Create a test bridge with a basic bridge configuration (name + IPv4).
defer netutils.SetupTestNetNS(t)()
createTestBridge(getBasicTestConfig(), t)
createTestBridge(getBasicTestConfig(), &bridgeInterface{}, t)
// Store various iptables chain rules we care for.
rules := []struct {
@ -39,37 +39,37 @@ func TestProgramIPTable(t *testing.T) {
func TestSetupIPTables(t *testing.T) {
// Create a test bridge with a basic bridge configuration (name + IPv4).
defer netutils.SetupTestNetNS(t)()
br := getBasicTestConfig()
createTestBridge(br, t)
config := getBasicTestConfig()
br := &bridgeInterface{}
createTestBridge(config, br, t)
// Modify iptables params in base configuration and apply them.
br.Config.EnableIPTables = true
assertBridgeConfig(br, t)
config.EnableIPTables = true
assertBridgeConfig(config, br, t)
br.Config.EnableIPMasquerade = true
assertBridgeConfig(br, t)
config.EnableIPMasquerade = true
assertBridgeConfig(config, br, t)
br.Config.EnableICC = true
assertBridgeConfig(br, t)
config.EnableICC = true
assertBridgeConfig(config, br, t)
br.Config.EnableIPMasquerade = false
assertBridgeConfig(br, t)
config.EnableIPMasquerade = false
assertBridgeConfig(config, br, t)
}
func getBasicTestConfig() *bridgeInterface {
return &bridgeInterface{
Config: &Configuration{
func getBasicTestConfig() *Configuration {
config := &Configuration{
BridgeName: DefaultBridgeName,
AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)},
},
}
AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)}}
return config
}
func createTestBridge(br *bridgeInterface, t *testing.T) {
if err := setupDevice(br); err != nil {
func createTestBridge(config *Configuration, br *bridgeInterface, t *testing.T) {
if err := setupDevice(config, br); err != nil {
t.Fatalf("Failed to create the testing Bridge: %s", err.Error())
}
if err := setupBridgeIPv4(br); err != nil {
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
}
}
@ -94,9 +94,9 @@ func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
}
// Assert function which pushes chains based on bridge config parameters.
func assertBridgeConfig(br *bridgeInterface, t *testing.T) {
func assertBridgeConfig(config *Configuration, br *bridgeInterface, t *testing.T) {
// Attempt programming of ip tables.
err := setupIPTables(br)
err := setupIPTables(config, br)
if err != nil {
t.Fatalf("%v", err)
}

View file

@ -41,13 +41,13 @@ func init() {
}
}
func setupBridgeIPv4(i *bridgeInterface) error {
bridgeIPv4, err := electBridgeIPv4(i.Config)
func setupBridgeIPv4(config *Configuration, i *bridgeInterface) error {
bridgeIPv4, err := electBridgeIPv4(config)
if err != nil {
return err
}
log.Debugf("Creating bridge interface %q with network %s", i.Config.BridgeName, bridgeIPv4)
log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
return fmt.Errorf("Failed to add IPv4 address %s to bridge: %v", bridgeIPv4, err)
}

View file

@ -8,16 +8,15 @@ import (
"github.com/vishvananda/netlink"
)
func setupTestInterface(t *testing.T) *bridgeInterface {
br := &bridgeInterface{
Config: &Configuration{
BridgeName: DefaultBridgeName,
},
}
if err := setupDevice(br); err != nil {
func setupTestInterface(t *testing.T) (*Configuration, *bridgeInterface) {
config := &Configuration{
BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
}
return br
return config, br
}
func TestSetupBridgeIPv4Fixed(t *testing.T) {
@ -28,9 +27,9 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
t.Fatalf("Failed to parse bridge IPv4: %v", err)
}
br := setupTestInterface(t)
br.Config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
if err := setupBridgeIPv4(br); err != nil {
config, br := setupTestInterface(t)
config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Failed to setup bridge IPv4: %v", err)
}
@ -41,22 +40,22 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
var found bool
for _, addr := range addrsv4 {
if br.Config.AddressIPv4.String() == addr.IPNet.String() {
if config.AddressIPv4.String() == addr.IPNet.String() {
found = true
break
}
}
if !found {
t.Fatalf("Bridge device does not have requested IPv4 address %v", br.Config.AddressIPv4)
t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4)
}
}
func TestSetupBridgeIPv4Auto(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := setupTestInterface(t)
if err := setupBridgeIPv4(br); err != nil {
config, br := setupTestInterface(t)
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Failed to setup bridge IPv4: %v", err)
}

View file

@ -22,9 +22,9 @@ func init() {
}
}
func setupBridgeIPv6(i *bridgeInterface) error {
func setupBridgeIPv6(config *Configuration, i *bridgeInterface) error {
// Enable IPv6 on the bridge
procFile := "/proc/sys/net/ipv6/conf/" + i.Config.BridgeName + "/disable_ipv6"
procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
}

View file

@ -13,12 +13,12 @@ import (
func TestSetupIPv6(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
br := setupTestInterface(t)
if err := setupBridgeIPv6(br); err != nil {
config, br := setupTestInterface(t)
if err := setupBridgeIPv6(config, br); err != nil {
t.Fatalf("Failed to setup bridge IPv6: %v", err)
}
procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", br.Config.BridgeName))
procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName))
if err != nil {
t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err)
}

View file

@ -6,7 +6,7 @@ import (
"github.com/vishvananda/netlink"
)
func setupVerifyConfiguredAddresses(i *bridgeInterface) error {
func setupVerifyConfiguredAddresses(config *Configuration, i *bridgeInterface) error {
// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
addrv4, addrsv6, err := i.addresses()
if err != nil {
@ -19,13 +19,13 @@ func setupVerifyConfiguredAddresses(i *bridgeInterface) error {
}
// Verify that the bridge IPv4 address matches the requested configuration.
if i.Config.AddressIPv4 != nil && !addrv4.IP.Equal(i.Config.AddressIPv4.IP) {
return fmt.Errorf("Bridge IPv4 (%s) does not match requested configuration %s", addrv4.IP, i.Config.AddressIPv4.IP)
if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
return fmt.Errorf("Bridge IPv4 (%s) does not match requested configuration %s", addrv4.IP, config.AddressIPv4.IP)
}
// Verify that one of the bridge IPv6 addresses matches the requested
// configuration.
if i.Config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
if config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
return fmt.Errorf("Bridge IPv6 addresses do not match the expected bridge configuration %s", bridgeIPv6)
}

View file

@ -9,7 +9,7 @@ import (
)
func setupVerifyTest(t *testing.T) *bridgeInterface {
inf := &bridgeInterface{Config: &Configuration{}}
inf := &bridgeInterface{}
br := netlink.Bridge{}
br.LinkAttrs.Name = "default0"
@ -27,13 +27,14 @@ func TestSetupVerify(t *testing.T) {
addrv4 := net.IPv4(192, 168, 1, 1)
inf := setupVerifyTest(t)
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
config := &Configuration{}
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
}
if err := setupVerifyConfiguredAddresses(inf); err != nil {
if err := setupVerifyConfiguredAddresses(config, inf); err != nil {
t.Fatalf("Address verification failed: %v", err)
}
}
@ -43,14 +44,15 @@ func TestSetupVerifyBad(t *testing.T) {
addrv4 := net.IPv4(192, 168, 1, 1)
inf := setupVerifyTest(t)
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
config := &Configuration{}
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
ipnet := &net.IPNet{IP: net.IPv4(192, 168, 1, 2), Mask: addrv4.DefaultMask()}
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: ipnet}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err)
}
if err := setupVerifyConfiguredAddresses(inf); err == nil {
if err := setupVerifyConfiguredAddresses(config, inf); err == nil {
t.Fatal("Address verification was expected to fail")
}
}
@ -60,9 +62,10 @@ func TestSetupVerifyMissing(t *testing.T) {
addrv4 := net.IPv4(192, 168, 1, 1)
inf := setupVerifyTest(t)
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
config := &Configuration{}
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
if err := setupVerifyConfiguredAddresses(inf); err == nil {
if err := setupVerifyConfiguredAddresses(config, inf); err == nil {
t.Fatal("Address verification was expected to fail")
}
}
@ -72,17 +75,18 @@ func TestSetupVerifyIPv6(t *testing.T) {
addrv4 := net.IPv4(192, 168, 1, 1)
inf := setupVerifyTest(t)
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
inf.Config.EnableIPv6 = true
config := &Configuration{}
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
config.EnableIPv6 = true
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err)
}
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
}
if err := setupVerifyConfiguredAddresses(inf); err != nil {
if err := setupVerifyConfiguredAddresses(config, inf); err != nil {
t.Fatalf("Address verification failed: %v", err)
}
}
@ -92,14 +96,15 @@ func TestSetupVerifyIPv6Missing(t *testing.T) {
addrv4 := net.IPv4(192, 168, 1, 1)
inf := setupVerifyTest(t)
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
inf.Config.EnableIPv6 = true
config := &Configuration{}
config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
config.EnableIPv6 = true
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
}
if err := setupVerifyConfiguredAddresses(inf); err == nil {
if err := setupVerifyConfiguredAddresses(config, inf); err == nil {
t.Fatal("Address verification was expected to fail")
}
}

View file

@ -1,7 +1,6 @@
package libnetwork_test
import (
"flag"
"net"
"testing"
@ -12,14 +11,9 @@ import (
"github.com/vishvananda/netlink"
)
var bridgeName = "docker0"
var enableBridgeTest = flag.Bool("enable-bridge-test", false, "")
var bridgeName = "dockertest0"
func TestSimplebridge(t *testing.T) {
if *enableBridgeTest == false {
t.Skip()
}
bridge := &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}
netlink.LinkDel(bridge)
@ -51,15 +45,30 @@ func TestSimplebridge(t *testing.T) {
"EnableIPTables": true,
"EnableIPMasquerade": true,
"EnableICC": true,
"EnableIPForwarding": true}
"EnableIPForwarding": true,
"AllowNonDefaultBridge": true}
controller := libnetwork.New()
network, err := controller.NewNetwork("simplebridge", "dummy", options)
driver, err := controller.NewNetworkDriver("simplebridge", options)
if err != nil {
t.Fatal(err)
}
network, err := controller.NewNetwork(driver, "testnetwork", "")
if err != nil {
t.Fatal(err)
}
ep, _, err := network.CreateEndpoint("testep", "", "")
if err != nil {
t.Fatal(err)
}
if err := ep.Delete(); err != nil {
t.Fatal(err)
}
if err := network.Delete(); err != nil {
t.Fatal(err)
}

View file

@ -5,9 +5,17 @@ create network namespaces and allocate interfaces for containers to use.
// Create a new controller instance
controller := libnetwork.New()
options := options.Generic{}
// This option is only needed for in-tree drivers. Plugins(in future) will get
// their options through plugin infrastructure.
option := options.Generic{}
driver, err := controller.NewNetworkDriver("simplebridge", option)
if err != nil {
return
}
netOptions := options.Generic{}
// Create a network for containers to join.
network, err := controller.NewNetwork("simplebridge", "network1", options)
network, err := controller.NewNetwork(driver, "network1", netOptions)
if err != nil {
return
}
@ -53,13 +61,14 @@ import (
// NetworkController provides the interface for controller instance which manages
// networks.
type NetworkController interface {
NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error)
// Create a new network. The options parameter carry driver specific options.
// Labels support will be added in the near future.
NewNetwork(networkType, name string, options interface{}) (Network, error)
NewNetwork(d *NetworkDriver, name string, options interface{}) (Network, error)
}
// A Network represents a logical connectivity zone that containers may
// ulteriorly join using the Link method. A Network is managed by a specific
// ulteriorly join using the CreateEndpoint method. A Network is managed by a specific
// driver.
type Network interface {
// A user chosen name for this network.
@ -86,6 +95,11 @@ type Endpoint interface {
Delete() error
}
// NetworkDriver provides a reference to driver and way to push driver specific config
type NetworkDriver struct {
internalDriver driverapi.Driver
}
type endpoint struct {
name string
id driverapi.UUID
@ -98,11 +112,13 @@ type network struct {
name string
networkType string
id driverapi.UUID
endpoints map[driverapi.UUID]*endpoint
driver *NetworkDriver
endpoints endpointTable
sync.Mutex
}
type networkTable map[driverapi.UUID]*network
type endpointTable map[driverapi.UUID]*endpoint
type controller struct {
networks networkTable
@ -115,18 +131,34 @@ func New() NetworkController {
return &controller{networkTable{}, enumerateDrivers(), sync.Mutex{}}
}
// NewNetwork creates a new network of the specified networkType. The options
// are driver specific and modeled in a generic way.
func (c *controller) NewNetwork(networkType, name string, options interface{}) (Network, error) {
network := &network{name: name, networkType: networkType}
network.id = driverapi.UUID(common.GenerateRandomID())
network.ctrlr = c
func (c *controller) NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error) {
d, ok := c.drivers[networkType]
if !ok {
return nil, fmt.Errorf("unknown driver %q", networkType)
}
if err := d.Config(options); err != nil {
return nil, err
}
return &NetworkDriver{internalDriver: d}, nil
}
// NewNetwork creates a new network of the specified networkType. The options
// are driver specific and modeled in a generic way.
func (c *controller) NewNetwork(nd *NetworkDriver, name string, options interface{}) (Network, error) {
network := &network{
name: name,
id: driverapi.UUID(common.GenerateRandomID()),
ctrlr: c,
driver: nd}
network.endpoints = make(endpointTable)
d := network.driver.internalDriver
if d == nil {
return nil, fmt.Errorf("invalid driver bound to network")
}
if err := d.CreateNetwork(network.id, options); err != nil {
return nil, err
}
@ -153,13 +185,8 @@ func (n *network) Type() string {
func (n *network) Delete() error {
var err error
d, ok := n.ctrlr.drivers[n.networkType]
if !ok {
return fmt.Errorf("unknown driver %q", n.networkType)
}
n.ctrlr.Lock()
_, ok = n.ctrlr.networks[n.id]
_, ok := n.ctrlr.networks[n.id]
if !ok {
n.ctrlr.Unlock()
return fmt.Errorf("unknown network %s id %s", n.name, n.id)
@ -183,6 +210,7 @@ func (n *network) Delete() error {
}
}()
d := n.driver.internalDriver
err = d.DeleteNetwork(n.id)
return err
}
@ -192,11 +220,7 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{
ep.id = driverapi.UUID(common.GenerateRandomID())
ep.network = n
d, ok := n.ctrlr.drivers[n.networkType]
if !ok {
return nil, nil, fmt.Errorf("unknown driver %q", n.networkType)
}
d := n.driver.internalDriver
sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options)
if err != nil {
return nil, nil, err
@ -212,14 +236,9 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{
func (ep *endpoint) Delete() error {
var err error
d, ok := ep.network.ctrlr.drivers[ep.network.networkType]
if !ok {
return fmt.Errorf("unknown driver %q", ep.network.networkType)
}
n := ep.network
n.Lock()
_, ok = n.endpoints[ep.id]
_, ok := n.endpoints[ep.id]
if !ok {
n.Unlock()
return fmt.Errorf("unknown endpoint %s id %s", ep.name, ep.id)
@ -235,6 +254,7 @@ func (ep *endpoint) Delete() error {
}
}()
d := n.driver.internalDriver
err = d.DeleteEndpoint(n.id, ep.id)
return err
}