Browse Source

- Added support to bridgeNetwork.Link
- Removed MAC and MTU configuration via AddInterface

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan 10 years ago
parent
commit
2d364e2c34

+ 0 - 14
libnetwork/configure.go

@@ -14,10 +14,8 @@ func configureInterface(iface netlink.Link, settings *Interface) error {
 		ErrMessage string
 	}{
 		{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, settings.DstName)},
-		{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC address to %q", ifaceName, settings.MacAddress)},
 		{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, settings.Address)},
 		{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, settings.AddressIPv6)},
-		{setInterfaceMTU, fmt.Sprintf("error setting interface %q MTU to %q", ifaceName, settings.MTU)},
 		{setInterfaceGateway, fmt.Sprintf("error setting interface %q gateway to %q", ifaceName, settings.Gateway)},
 		{setInterfaceGatewayIPv6, fmt.Sprintf("error setting interface %q IPv6 gateway to %q", ifaceName, settings.GatewayIPv6)},
 	}
@@ -78,18 +76,6 @@ func setInterfaceIPv6(iface netlink.Link, settings *Interface) (err error) {
 	return err
 }
 
-func setInterfaceMAC(iface netlink.Link, settings *Interface) (err error) {
-	var hwAddr net.HardwareAddr
-	if hwAddr, err = net.ParseMAC(settings.MacAddress); err == nil {
-		err = netlink.LinkSetHardwareAddr(iface, hwAddr)
-	}
-	return err
-}
-
-func setInterfaceMTU(iface netlink.Link, settings *Interface) error {
-	return netlink.LinkSetMTU(iface, settings.MTU)
-}
-
 func setInterfaceName(iface netlink.Link, settings *Interface) error {
 	return netlink.LinkSetName(iface, settings.DstName)
 }

+ 9 - 3
libnetwork/drivers/bridge/interface.go

@@ -1,6 +1,10 @@
 package bridge
 
-import "github.com/vishvananda/netlink"
+import (
+	"net"
+
+	"github.com/vishvananda/netlink"
+)
 
 const (
 	// DefaultBridgeName is the default name for the bridge interface managed
@@ -10,8 +14,10 @@ const (
 
 // Interface models the bridge network device.
 type bridgeInterface struct {
-	Config *Configuration
-	Link   netlink.Link
+	Config     *Configuration
+	Link       netlink.Link
+	bridgeIPv4 *net.IPNet
+	bridgeIPv6 *net.IPNet
 }
 
 // NewInterface creates a new bridge interface structure. It attempts to find

+ 103 - 2
libnetwork/drivers/bridge/network.go

@@ -1,13 +1,23 @@
 package bridge
 
 import (
+	"errors"
+	"net"
+	"strings"
+
+	"github.com/docker/libcontainer/utils"
 	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/ipallocator"
 	"github.com/vishvananda/netlink"
 )
 
+// ErrEndpointExists is returned if more than one endpoint is added to the network
+var ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
+
 type bridgeNetwork struct {
 	NetworkName string
 	bridge      *bridgeInterface
+	EndPoint    *libnetwork.Interface
 }
 
 func (b *bridgeNetwork) Name() string {
@@ -19,8 +29,99 @@ func (b *bridgeNetwork) Type() string {
 }
 
 func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) {
-	// TODO
-	return nil, nil
+
+	var ipv6Addr net.IPNet
+
+	if b.EndPoint != nil {
+		return nil, ErrEndpointExists
+	}
+
+	name1, err := generateIfaceName()
+	if err != nil {
+		return nil, err
+	}
+
+	name2, err := generateIfaceName()
+	if err != nil {
+		return nil, err
+	}
+
+	veth := &netlink.Veth{
+		LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
+		PeerName:  name2}
+	if err := netlink.LinkAdd(veth); err != nil {
+		return nil, err
+	}
+
+	host, err := netlink.LinkByName(name1)
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			netlink.LinkDel(host)
+		}
+	}()
+
+	container, err := netlink.LinkByName(name2)
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			netlink.LinkDel(container)
+		}
+	}()
+
+	if err = netlink.LinkSetMaster(host,
+		&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: b.bridge.Config.BridgeName}}); err != nil {
+		return nil, err
+	}
+
+	ip4, err := ipallocator.RequestIP(b.bridge.bridgeIPv4, nil)
+	if err != nil {
+		return nil, err
+	}
+	ipv4Addr := net.IPNet{IP: ip4, Mask: b.bridge.bridgeIPv4.Mask}
+
+	if b.bridge.Config.EnableIPv6 {
+		ip6, err := ipallocator.RequestIP(b.bridge.bridgeIPv6, nil)
+		if err != nil {
+			return nil, err
+		}
+		ipv6Addr = net.IPNet{IP: ip6, Mask: b.bridge.bridgeIPv6.Mask}
+	}
+
+	var interfaces []*libnetwork.Interface
+	intf := &libnetwork.Interface{}
+	intf.SrcName = name2
+	intf.DstName = "eth0"
+	intf.Address = ipv4Addr.String()
+	intf.Gateway = b.bridge.bridgeIPv4.IP.String()
+	if b.bridge.Config.EnableIPv6 {
+		intf.AddressIPv6 = ipv6Addr.String()
+		intf.GatewayIPv6 = b.bridge.bridgeIPv6.IP.String()
+	}
+
+	b.EndPoint = intf
+	interfaces = append(interfaces, intf)
+	return interfaces, nil
+}
+
+func generateIfaceName() (string, error) {
+	for i := 0; i < 10; i++ {
+		name, err := utils.GenerateRandomName("veth", 7)
+		if err != nil {
+			continue
+		}
+		if _, err := net.InterfaceByName(name); err != nil {
+			if strings.Contains(err.Error(), "no such") {
+				return name, nil
+			}
+			return "", err
+		}
+	}
+	return "", errors.New("Failed to find name for new interface")
 }
 
 func (b *bridgeNetwork) Delete() error {

+ 119 - 0
libnetwork/drivers/bridge/network_test.go

@@ -0,0 +1,119 @@
+package bridge
+
+import (
+	"net"
+	"testing"
+
+	"github.com/docker/libnetwork"
+	"github.com/vishvananda/netlink"
+)
+
+func TestLinkCreate(t *testing.T) {
+	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
+
+	config := &Configuration{
+		BridgeName: DefaultBridgeName,
+		EnableIPv6: true}
+	netw, err := d.CreateNetwork("dummy", config)
+	if err != nil {
+		t.Fatalf("Failed to create bridge: %v", err)
+	}
+
+	interfaces, err := netw.Link("ep")
+	if err != nil {
+		t.Fatalf("Failed to create a link: %v", err)
+	}
+
+	if len(interfaces) != 1 {
+		t.Fatalf("Expected exactly one interface. Instead got %d interface(s)", len(interfaces))
+	}
+
+	if interfaces[0].DstName == "" {
+		t.Fatal("Invalid Dstname returned")
+	}
+
+	_, err = netlink.LinkByName(interfaces[0].SrcName)
+	if err != nil {
+		t.Fatalf("Could not find source link %s: %v", interfaces[0].SrcName, err)
+	}
+
+	ip, _, err := net.ParseCIDR(interfaces[0].Address)
+	if err != nil {
+		t.Fatalf("Invalid IPv4 address returned, ip = %s: %v", interfaces[0].Address, err)
+	}
+
+	b := netw.(*bridgeNetwork)
+	if !b.bridge.bridgeIPv4.Contains(ip) {
+		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), b.bridge.bridgeIPv4.String())
+	}
+
+	ip6, _, err := net.ParseCIDR(interfaces[0].AddressIPv6)
+	if err != nil {
+		t.Fatalf("Invalid IPv6 address returned, ip = %s: %v", interfaces[0].AddressIPv6, err)
+	}
+
+	if !b.bridge.bridgeIPv6.Contains(ip6) {
+		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
+	}
+
+	if interfaces[0].Gateway != b.bridge.bridgeIPv4.IP.String() {
+		t.Fatalf("Invalid default gateway. Expected %s. Got %s", b.bridge.bridgeIPv4.IP.String(),
+			interfaces[0].Gateway)
+	}
+
+	if interfaces[0].GatewayIPv6 != b.bridge.bridgeIPv6.IP.String() {
+		t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", b.bridge.bridgeIPv6.IP.String(),
+			interfaces[0].GatewayIPv6)
+	}
+}
+
+func TestLinkCreateTwo(t *testing.T) {
+	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
+
+	config := &Configuration{
+		BridgeName: DefaultBridgeName,
+		EnableIPv6: true}
+	netw, err := d.CreateNetwork("dummy", config)
+	if err != nil {
+		t.Fatalf("Failed to create bridge: %v", err)
+	}
+
+	_, err = netw.Link("ep")
+	if err != nil {
+		t.Fatalf("Failed to create a link: %v", err)
+	}
+
+	_, err = netw.Link("ep1")
+	if err != nil {
+		if err != ErrEndpointExists {
+			t.Fatalf("Failed with a wrong error :%v", err)
+		}
+	} else {
+		t.Fatalf("Expected to fail while trying to add more than one endpoint")
+	}
+}
+
+func TestLinkCreateNoEnableIPv6(t *testing.T) {
+	defer libnetwork.SetupTestNetNS(t)()
+	d := &driver{}
+
+	config := &Configuration{
+		BridgeName: DefaultBridgeName}
+	netw, err := d.CreateNetwork("dummy", config)
+	if err != nil {
+		t.Fatalf("Failed to create bridge: %v", err)
+	}
+
+	interfaces, err := netw.Link("ep")
+	if err != nil {
+		t.Fatalf("Failed to create a link: %v", err)
+	}
+
+	if interfaces[0].AddressIPv6 != "" ||
+		interfaces[0].GatewayIPv6 != "" {
+		t.Fatalf("Expected IPv6 address and GatewayIPv6 to be empty when IPv6 enabled. Instead got IPv6 = %s and GatewayIPv6 = %s",
+			interfaces[0].AddressIPv6, interfaces[0].GatewayIPv6)
+	}
+}

+ 2 - 0
libnetwork/drivers/bridge/setup_ipv4.go

@@ -52,6 +52,8 @@ func setupBridgeIPv4(i *bridgeInterface) error {
 		return fmt.Errorf("Failed to add IPv4 address %s to bridge: %v", bridgeIPv4, err)
 	}
 
+	i.bridgeIPv4 = bridgeIPv4
+
 	return nil
 }
 

+ 2 - 0
libnetwork/drivers/bridge/setup_ipv6.go

@@ -33,5 +33,7 @@ func setupBridgeIPv6(i *bridgeInterface) error {
 		return fmt.Errorf("Failed to add IPv6 address %s to bridge: %v", bridgeIPv6, err)
 	}
 
+	i.bridgeIPv6 = bridgeIPv6
+
 	return nil
 }

+ 0 - 6
libnetwork/network.go

@@ -44,9 +44,6 @@ type Interface struct {
 	// network namespace.
 	DstName string
 
-	// MAC address for the interface.
-	MacAddress string
-
 	// IPv4 address for the interface.
 	Address string
 
@@ -58,9 +55,6 @@ type Interface struct {
 
 	// IPv6 gateway for the interface.
 	GatewayIPv6 string
-
-	// Network MTU.
-	MTU int
 }
 
 // A Network represents a logical connectivity zone that containers may