Libnetwork bridge to handle --mac-address option

- This addresses one requirement from Issue #79
- Defined EndpointConfiguration struct for bridge driver
  which contains the user's preferred mac address for the
  sanbox interface

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2015-04-23 11:15:15 -07:00
parent 584aaeac36
commit 69437b1009
7 changed files with 97 additions and 20 deletions

View File

@ -35,7 +35,7 @@ func main() {
// settings will be used for container infos (inspect and such), as well as
// iptables rules for port publishing. This info is contained or accessible
// from the returned endpoint.
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
if err != nil {
return
}

View File

@ -41,9 +41,15 @@ type Configuration struct {
AllowNonDefaultBridge bool
}
// EndpointConfiguration represents the user specified configuration for the sandbox endpoint
type EndpointConfiguration struct {
MacAddress net.HardwareAddr
}
type bridgeEndpoint struct {
id types.UUID
port *sandbox.Interface
id types.UUID
port *sandbox.Interface
config *EndpointConfiguration // User specified parameters
}
type bridgeNetwork struct {
@ -239,7 +245,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
return err
}
func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption interface{}) (*sandbox.Info, error) {
func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions interface{}) (*sandbox.Info, error) {
var (
ipv6Addr *net.IPNet
err error
@ -285,8 +291,14 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
return nil, driverapi.ErrEndpointExists
}
// Try to convert the options to endpoint configuration
epConfig, err := parseEndpointOptions(epOptions)
if err != nil {
return nil, err
}
// Create and add the endpoint
endpoint := &bridgeEndpoint{id: eid}
endpoint := &bridgeEndpoint{id: eid, config: epConfig}
n.endpoints[sboxKey] = endpoint
n.Unlock()
@ -335,6 +347,15 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
if err != nil {
return nil, err
}
// Add user specified attributes
if epConfig != nil && epConfig.MacAddress != nil {
err = netlink.LinkSetHardwareAddr(sbox, epConfig.MacAddress)
if err != nil {
return nil, err
}
}
defer func() {
if err != nil {
netlink.LinkDel(sbox)
@ -347,14 +368,14 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
return nil, err
}
// Reuqest a v4 address for the sandbox side pipe interface
// v4 address for the sandbox side pipe interface
ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
if err != nil {
return nil, err
}
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
// Request a v6 address for the sandbox side pipe interface
// v6 address for the sandbox side pipe interface
if config.EnableIPv6 {
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
if err != nil {
@ -454,6 +475,24 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
return nil
}
func parseEndpointOptions(epOptions interface{}) (*EndpointConfiguration, error) {
if epOptions == nil {
return nil, nil
}
switch opt := epOptions.(type) {
case options.Generic:
opaqueConfig, err := options.GenerateFromModel(opt, &EndpointConfiguration{})
if err != nil {
return nil, err
}
return opaqueConfig.(*EndpointConfiguration), nil
case *EndpointConfiguration:
return opt, nil
default:
return nil, ErrInvalidEndpointConfig
}
}
// Generates a name to be used for a virtual ethernet
// interface. The name is constructed by 'veth' appended
// by a randomly generated hex value. (example: veth0f60e2c)

View File

@ -1,10 +1,12 @@
package bridge
import (
"bytes"
"net"
"testing"
"github.com/docker/libnetwork/netutils"
"github.com/vishvananda/netlink"
)
func TestCreate(t *testing.T) {
@ -56,3 +58,36 @@ func TestCreateFullOptions(t *testing.T) {
t.Fatalf("Failed to create bridge: %v", err)
}
}
func TestCreateLinkWithOptions(t *testing.T) {
defer netutils.SetupTestNetNS(t)()
_, d := New()
config := &Configuration{BridgeName: DefaultBridgeName}
if err := d.Config(config); err != nil {
t.Fatalf("Failed to setup driver config: %v", err)
}
err := d.CreateNetwork("net1", "")
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
epConf := &EndpointConfiguration{MacAddress: mac}
sinfo, err := d.CreateEndpoint("net1", "ep", "s1", epConf)
if err != nil {
t.Fatalf("Failed to create a link: %s", err.Error())
}
ifaceName := sinfo.Interfaces[0].SrcName
veth, err := netlink.LinkByName(ifaceName)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(mac, veth.Attrs().HardwareAddr) {
t.Fatalf("Failed to parse and program endpoint configuration")
}
}

View File

@ -13,6 +13,9 @@ var (
// ErrInvalidConfig error is returned when a network is created on a driver without valid config.
ErrInvalidConfig = errors.New("trying to create a network on a driver without valid config")
// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
ErrInvalidEndpointConfig = errors.New("trying to create an endpoint with an invalid endpoint configuration")
// ErrNetworkExists error is returned when a network already exists and another network is created.
ErrNetworkExists = errors.New("network already exists, simplebridge can only have one network")

View File

@ -25,7 +25,7 @@ func TestLinkCreate(t *testing.T) {
t.Fatalf("Failed to create bridge: %v", err)
}
sinfo, err := d.CreateEndpoint("dummy", "", "sb1", "")
sinfo, err := d.CreateEndpoint("dummy", "", "sb1", nil)
if err != nil {
if _, ok := err.(InvalidEndpointIDError); !ok {
t.Fatalf("Failed with a wrong error :%s", err.Error())
@ -34,7 +34,7 @@ func TestLinkCreate(t *testing.T) {
t.Fatalf("Failed to detect invalid config")
}
sinfo, err = d.CreateEndpoint("dummy", "ep", "", "")
sinfo, err = d.CreateEndpoint("dummy", "ep", "", nil)
if err != nil {
if _, ok := err.(InvalidSandboxIDError); !ok {
t.Fatalf("Failed with a wrong error :%s", err.Error())
@ -43,17 +43,17 @@ func TestLinkCreate(t *testing.T) {
t.Fatalf("Failed to detect invalid config")
}
sinfo, err = d.CreateEndpoint("dummy", "ep", "cc", "")
sinfo, err = d.CreateEndpoint("dummy", "ep", "cc", nil)
if err != nil {
t.Fatalf("Failed to create a link: %s", err.Error())
}
_, err = d.CreateEndpoint("dummy", "ep", "cc2", "")
_, err = d.CreateEndpoint("dummy", "ep", "cc2", nil)
if err == nil {
t.Fatalf("Failed to detect duplicate endpoint id on same network")
}
_, err = d.CreateEndpoint("dummy", "ep2", "cc", "")
_, err = d.CreateEndpoint("dummy", "ep2", "cc", nil)
if err == nil {
t.Fatalf("Failed to detect addition of more than one endpoint to same sandbox")
}
@ -110,12 +110,12 @@ func TestLinkCreateTwo(t *testing.T) {
t.Fatalf("Failed to create bridge: %v", err)
}
_, err = d.CreateEndpoint("dummy", "ep", "s1", "")
_, err = d.CreateEndpoint("dummy", "ep", "s1", nil)
if err != nil {
t.Fatalf("Failed to create a link: %s", err.Error())
}
_, err = d.CreateEndpoint("dummy", "ep", "s1", "")
_, err = d.CreateEndpoint("dummy", "ep", "s1", nil)
if err != nil {
if err != driverapi.ErrEndpointExists {
t.Fatalf("Failed with a wrong error :%s", err.Error())
@ -140,7 +140,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
t.Fatalf("Failed to create bridge: %v", err)
}
sinfo, err := d.CreateEndpoint("dummy", "ep", "sb2", "")
sinfo, err := d.CreateEndpoint("dummy", "ep", "sb2", nil)
if err != nil {
t.Fatalf("Failed to create a link: %s", err.Error())
}
@ -171,7 +171,7 @@ func TestLinkDelete(t *testing.T) {
t.Fatalf("Failed to create bridge: %v", err)
}
_, err = d.CreateEndpoint("dummy", "ep1", "s1", "")
_, err = d.CreateEndpoint("dummy", "ep1", "s1", nil)
if err != nil {
t.Fatalf("Failed to create a link: %s", err.Error())
}

View File

@ -67,7 +67,7 @@ func TestSimplebridge(t *testing.T) {
t.Fatal(err)
}
ep, err := network.CreateEndpoint("testep", "sb1", "")
ep, err := network.CreateEndpoint("testep", "sb1", nil)
if err != nil {
t.Fatal(err)
}
@ -205,7 +205,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
t.Fatal(err)
}
ep, err := network.CreateEndpoint("testep", "sb2", "")
ep, err := network.CreateEndpoint("testep", "sb2", nil)
if err != nil {
t.Fatal(err)
}
@ -273,7 +273,7 @@ func TestUnknownEndpoint(t *testing.T) {
t.Fatal(err)
}
ep, err := network.CreateEndpoint("testep", "sb1", "")
ep, err := network.CreateEndpoint("testep", "sb1", nil)
if err != nil {
t.Fatal(err)
}

View File

@ -31,7 +31,7 @@ create network namespaces and allocate interfaces for containers to use.
// For each new container: allocate IP and interfaces. The returned network
// settings will be used for container infos (inspect and such), as well as
// iptables rules for port publishing.
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
if err != nil {
return
}