mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #84 from aboch/mao
Libnetwork bridge to handle --mac-address option
This commit is contained in:
commit
914ad10ea4
7 changed files with 97 additions and 20 deletions
|
@ -35,7 +35,7 @@ func main() {
|
||||||
// settings will be used for container infos (inspect and such), as well as
|
// settings will be used for container infos (inspect and such), as well as
|
||||||
// iptables rules for port publishing. This info is contained or accessible
|
// iptables rules for port publishing. This info is contained or accessible
|
||||||
// from the returned endpoint.
|
// from the returned endpoint.
|
||||||
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,15 @@ type Configuration struct {
|
||||||
AllowNonDefaultBridge bool
|
AllowNonDefaultBridge bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EndpointConfiguration represents the user specified configuration for the sandbox endpoint
|
||||||
|
type EndpointConfiguration struct {
|
||||||
|
MacAddress net.HardwareAddr
|
||||||
|
}
|
||||||
|
|
||||||
type bridgeEndpoint struct {
|
type bridgeEndpoint struct {
|
||||||
id types.UUID
|
id types.UUID
|
||||||
port *sandbox.Interface
|
port *sandbox.Interface
|
||||||
|
config *EndpointConfiguration // User specified parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
type bridgeNetwork struct {
|
type bridgeNetwork struct {
|
||||||
|
@ -239,7 +245,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||||
return err
|
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 (
|
var (
|
||||||
ipv6Addr *net.IPNet
|
ipv6Addr *net.IPNet
|
||||||
err error
|
err error
|
||||||
|
@ -285,8 +291,14 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
|
||||||
return nil, driverapi.ErrEndpointExists
|
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
|
// Create and add the endpoint
|
||||||
endpoint := &bridgeEndpoint{id: eid}
|
endpoint := &bridgeEndpoint{id: eid, config: epConfig}
|
||||||
n.endpoints[sboxKey] = endpoint
|
n.endpoints[sboxKey] = endpoint
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
|
||||||
|
@ -335,6 +347,15 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
netlink.LinkDel(sbox)
|
netlink.LinkDel(sbox)
|
||||||
|
@ -347,14 +368,14 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOption in
|
||||||
return nil, err
|
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)
|
ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
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 {
|
if config.EnableIPv6 {
|
||||||
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
|
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -454,6 +475,24 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
return nil
|
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
|
// Generates a name to be used for a virtual ethernet
|
||||||
// interface. The name is constructed by 'veth' appended
|
// interface. The name is constructed by 'veth' appended
|
||||||
// by a randomly generated hex value. (example: veth0f60e2c)
|
// by a randomly generated hex value. (example: veth0f60e2c)
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
|
@ -56,3 +58,36 @@ func TestCreateFullOptions(t *testing.T) {
|
||||||
t.Fatalf("Failed to create bridge: %v", err)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ var (
|
||||||
// ErrInvalidConfig error is returned when a network is created on a driver without valid config.
|
// 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")
|
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 error is returned when a network already exists and another network is created.
|
||||||
ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
|
ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestLinkCreate(t *testing.T) {
|
||||||
t.Fatalf("Failed to create bridge: %v", err)
|
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 err != nil {
|
||||||
if _, ok := err.(InvalidEndpointIDError); !ok {
|
if _, ok := err.(InvalidEndpointIDError); !ok {
|
||||||
t.Fatalf("Failed with a wrong error :%s", err.Error())
|
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")
|
t.Fatalf("Failed to detect invalid config")
|
||||||
}
|
}
|
||||||
|
|
||||||
sinfo, err = d.CreateEndpoint("dummy", "ep", "", "")
|
sinfo, err = d.CreateEndpoint("dummy", "ep", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(InvalidSandboxIDError); !ok {
|
if _, ok := err.(InvalidSandboxIDError); !ok {
|
||||||
t.Fatalf("Failed with a wrong error :%s", err.Error())
|
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")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
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 {
|
if err == nil {
|
||||||
t.Fatalf("Failed to detect duplicate endpoint id on same network")
|
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 {
|
if err == nil {
|
||||||
t.Fatalf("Failed to detect addition of more than one endpoint to same sandbox")
|
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)
|
t.Fatalf("Failed to create bridge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = d.CreateEndpoint("dummy", "ep", "s1", "")
|
_, err = d.CreateEndpoint("dummy", "ep", "s1", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
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 != nil {
|
||||||
if err != driverapi.ErrEndpointExists {
|
if err != driverapi.ErrEndpointExists {
|
||||||
t.Fatalf("Failed with a wrong error :%s", err.Error())
|
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)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
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)
|
t.Fatalf("Failed to create bridge: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = d.CreateEndpoint("dummy", "ep1", "s1", "")
|
_, err = d.CreateEndpoint("dummy", "ep1", "s1", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func Testbridge(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, err := network.CreateEndpoint("testep", "sb1", "")
|
ep, err := network.CreateEndpoint("testep", "sb1", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, err := network.CreateEndpoint("testep", "sb2", "")
|
ep, err := network.CreateEndpoint("testep", "sb2", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ func TestUnknownEndpoint(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, err := network.CreateEndpoint("testep", "sb1", "")
|
ep, err := network.CreateEndpoint("testep", "sb1", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// For each new container: allocate IP and interfaces. The returned network
|
||||||
// settings will be used for container infos (inspect and such), as well as
|
// settings will be used for container infos (inspect and such), as well as
|
||||||
// iptables rules for port publishing.
|
// iptables rules for port publishing.
|
||||||
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue