Przeglądaj źródła

Merge pull request #63 from aboch/qr

Enhance Endpoint interface
Madhu Venugopal 10 lat temu
rodzic
commit
d48f2c1a8e

+ 5 - 3
libnetwork/README.md

@@ -48,13 +48,15 @@ There are many networking solutions available to suit a broad range of use-cases
  
  // 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.
- _, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
+ // iptables rules for port publishing. This info is contained or accessible
+ // from the returned endpoint.
+ ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
  if err != nil {
     return
  }
- 
+
  // Add interfaces to the namespace.
+ sinfo := ep.SandboxInfo()
  for _, iface := range sinfo.Interfaces {
      if err := networkNamespace.AddInterface(iface); err != nil {
      	    return

+ 4 - 2
libnetwork/cmd/readme_test/readme.go

@@ -33,13 +33,15 @@ func main() {
 
 	// 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.
-	_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
+	// iptables rules for port publishing. This info is contained or accessible
+	// from the returned endpoint.
+	ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
 	if err != nil {
 		return
 	}
 
 	// Add interfaces to the namespace.
+	sinfo := ep.SandboxInfo()
 	for _, iface := range sinfo.Interfaces {
 		if err := networkNamespace.AddInterface(iface); err != nil {
 			return

+ 86 - 2
libnetwork/driverapi/driverapi.go

@@ -3,6 +3,8 @@ package driverapi
 import (
 	"errors"
 	"net"
+
+	"github.com/docker/libnetwork/netutils"
 )
 
 var (
@@ -56,10 +58,10 @@ type Interface struct {
 	DstName string
 
 	// IPv4 address for the interface.
-	Address net.IPNet
+	Address *net.IPNet
 
 	// IPv6 address for the interface.
-	AddressIPv6 net.IPNet
+	AddressIPv6 *net.IPNet
 }
 
 // SandboxInfo represents all possible information that
@@ -76,3 +78,85 @@ type SandboxInfo struct {
 
 	// TODO: Add routes and ip tables etc.
 }
+
+// GetCopy returns a copy of this Interface structure
+func (i *Interface) GetCopy() *Interface {
+	return &Interface{
+		SrcName:     i.SrcName,
+		DstName:     i.DstName,
+		Address:     netutils.GetIPNetCopy(i.Address),
+		AddressIPv6: netutils.GetIPNetCopy(i.AddressIPv6),
+	}
+}
+
+// Equal checks if this instance of Interface is equal to the passed one
+func (i *Interface) Equal(o *Interface) bool {
+	if i == o {
+		return true
+	}
+
+	if o == nil {
+		return false
+	}
+
+	if i.SrcName != o.SrcName || i.DstName != o.DstName {
+		return false
+	}
+
+	if !netutils.CompareIPNet(i.Address, o.Address) {
+		return false
+	}
+
+	if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
+		return false
+	}
+
+	return true
+}
+
+// GetCopy returns a copy of this SandboxInfo structure
+func (s *SandboxInfo) GetCopy() *SandboxInfo {
+	list := make([]*Interface, len(s.Interfaces))
+	for i, iface := range s.Interfaces {
+		list[i] = iface.GetCopy()
+	}
+	gw := netutils.GetIPCopy(s.Gateway)
+	gw6 := netutils.GetIPCopy(s.GatewayIPv6)
+
+	return &SandboxInfo{Interfaces: list, Gateway: gw, GatewayIPv6: gw6}
+}
+
+// Equal checks if this instance of SandboxInfo is equal to the passed one
+func (s *SandboxInfo) Equal(o *SandboxInfo) bool {
+	if s == o {
+		return true
+	}
+
+	if o == nil {
+		return false
+	}
+
+	if !s.Gateway.Equal(o.Gateway) {
+		return false
+	}
+
+	if !s.GatewayIPv6.Equal(o.GatewayIPv6) {
+		return false
+	}
+
+	if (s.Interfaces == nil && o.Interfaces != nil) ||
+		(s.Interfaces != nil && o.Interfaces == nil) ||
+		(len(s.Interfaces) != len(o.Interfaces)) {
+		return false
+	}
+
+	// Note: At the moment, the two lists must be in the same order
+	for i := 0; i < len(s.Interfaces); i++ {
+		if !s.Interfaces[i].Equal(o.Interfaces[i]) {
+			return false
+		}
+	}
+
+	return true
+
+}

+ 71 - 0
libnetwork/driverapi/driverapi_test.go

@@ -0,0 +1,71 @@
+package driverapi
+
+import (
+	"net"
+	"testing"
+)
+
+func TestInterfaceEqual(t *testing.T) {
+	list := getInterfaceList()
+
+	if !list[0].Equal(list[0]) {
+		t.Fatalf("Interface.Equal() returned false negative")
+	}
+
+	if list[0].Equal(list[1]) {
+		t.Fatalf("Interface.Equal() returned false positive")
+	}
+
+	if list[0].Equal(list[1]) != list[1].Equal(list[0]) {
+		t.Fatalf("Interface.Equal() failed commutative check")
+	}
+}
+
+func TestInterfaceCopy(t *testing.T) {
+	for _, iface := range getInterfaceList() {
+		cp := iface.GetCopy()
+
+		if !iface.Equal(cp) {
+			t.Fatalf("Failed to return a copy of Interface")
+		}
+
+		if iface == cp {
+			t.Fatalf("Failed to return a true copy of Interface")
+		}
+	}
+}
+
+func TestSandboxInfoCopy(t *testing.T) {
+	si := SandboxInfo{Interfaces: getInterfaceList(), Gateway: net.ParseIP("192.168.1.254"), GatewayIPv6: net.ParseIP("2001:2345::abcd:8889")}
+	cp := si.GetCopy()
+
+	if !si.Equal(cp) {
+		t.Fatalf("Failed to return a copy of SandboxInfo")
+	}
+
+	if &si == cp {
+		t.Fatalf("Failed to return a true copy of SanboxInfo")
+	}
+}
+
+func getInterfaceList() []*Interface {
+	_, netv4a, _ := net.ParseCIDR("192.168.30.1/24")
+	_, netv4b, _ := net.ParseCIDR("172.18.255.2/23")
+	_, netv6a, _ := net.ParseCIDR("2001:2345::abcd:8888/80")
+	_, netv6b, _ := net.ParseCIDR("2001:2345::abcd:8889/80")
+
+	return []*Interface{
+		&Interface{
+			SrcName:     "veth1234567",
+			DstName:     "eth0",
+			Address:     netv4a,
+			AddressIPv6: netv6a,
+		},
+		&Interface{
+			SrcName:     "veth7654321",
+			DstName:     "eth1",
+			Address:     netv4b,
+			AddressIPv6: netv6b,
+		},
+	}
+}

+ 5 - 4
libnetwork/drivers/bridge/bridge.go

@@ -213,7 +213,8 @@ func (d *driver) DeleteNetwork(nid driverapi.UUID) error {
 
 func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOption interface{}) (*driverapi.SandboxInfo, error) {
 	var (
-		ipv6Addr net.IPNet
+		ipv6Addr *net.IPNet
+		ip6      net.IP
 		err      error
 	)
 
@@ -292,14 +293,14 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOptio
 	if err != nil {
 		return nil, err
 	}
-	ipv4Addr := net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
+	ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
 
 	if config.EnableIPv6 {
 		ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
 		if err != nil {
 			return nil, err
 		}
-		ipv6Addr = net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
+		ipv6Addr = &net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
 	}
 
 	var interfaces []*driverapi.Interface
@@ -316,7 +317,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, epOptio
 	}
 
 	n.endpoint.addressIPv4 = ip4
-	n.endpoint.addressIPv6 = ipv6Addr.IP
+	n.endpoint.addressIPv6 = ip6
 	interfaces = append(interfaces, intf)
 	sinfo.Interfaces = interfaces
 	return sinfo, nil

+ 1 - 1
libnetwork/drivers/bridge/network_test.go

@@ -118,7 +118,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
 	}
 
 	interfaces := sinfo.Interfaces
-	if len(interfaces[0].AddressIPv6.IP) != 0 {
+	if interfaces[0].AddressIPv6 != nil {
 		t.Fatalf("Expectd IPv6 address to be nil when IPv6 is not enabled. Got IPv6 = %s", interfaces[0].AddressIPv6.String())
 	}
 

+ 3 - 3
libnetwork/libnetwork_test.go

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

+ 29 - 0
libnetwork/netutils/utils.go

@@ -3,6 +3,7 @@
 package netutils
 
 import (
+	"bytes"
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
@@ -145,3 +146,31 @@ func GenerateRandomName(prefix string, size int) (string, error) {
 	}
 	return prefix + hex.EncodeToString(id)[:size], nil
 }
+
+// GetIPCopy returns a copy of the passed IP address
+func GetIPCopy(from net.IP) net.IP {
+	to := make(net.IP, len(from))
+	copy(to, from)
+	return to
+}
+
+// GetIPNetCopy returns a copy of the passed IP Network
+func GetIPNetCopy(from *net.IPNet) *net.IPNet {
+	if from == nil {
+		return nil
+	}
+	bm := make(net.IPMask, len(from.Mask))
+	copy(bm, from.Mask)
+	return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
+}
+
+// CompareIPNet returns equal if the two IP Networks are equal
+func CompareIPNet(a, b *net.IPNet) bool {
+	if a == b {
+		return true
+	}
+	if a == nil || b == nil {
+		return false
+	}
+	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
+}

+ 52 - 0
libnetwork/netutils/utils_test.go

@@ -209,3 +209,55 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
 		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
 	}
 }
+
+func TestCompareIPNet(t *testing.T) {
+	if CompareIPNet(nil, nil) == false {
+		t.Fatalf("Failed to detect two nil net.IPNets are equal")
+	}
+
+	_, net1, _ := net.ParseCIDR("192.168.30.22/24")
+	if CompareIPNet(net1, net1) == false {
+		t.Fatalf("Failed to detect same net.IPNet pointers equality")
+	}
+
+	_, net2, _ := net.ParseCIDR("192.168.30.22/24")
+	if CompareIPNet(net1, net2) == false {
+		t.Fatalf("Failed to detect same net.IPNet object equality")
+	}
+
+	_, net3, _ := net.ParseCIDR("192.168.30.33/24")
+	if CompareIPNet(net1, net3) == false {
+		t.Fatalf("Failed to detect semantically equivalent net.IPNets")
+	}
+
+	_, net3, _ = net.ParseCIDR("192.168.31.33/24")
+	if CompareIPNet(net2, net3) == true {
+		t.Fatalf("Failed to detect different net.IPNets")
+	}
+}
+
+func TestIPCopyFunctions(t *testing.T) {
+	ip := net.ParseIP("172.28.30.134")
+	cp := GetIPCopy(ip)
+
+	if !ip.Equal(cp) {
+		t.Fatalf("Failed to return a copy of net.IP")
+	}
+
+	if &ip == &cp {
+		t.Fatalf("Failed to return a true copy of net.IP")
+	}
+}
+
+func TestNetIPCopyFunctions(t *testing.T) {
+	_, net, _ := net.ParseCIDR("192.168.30.23/24")
+	cp := GetIPNetCopy(net)
+
+	if CompareIPNet(net, cp) == false {
+		t.Fatalf("Failed to return a copy of net.IPNet")
+	}
+
+	if net == cp {
+		t.Fatalf("Failed to return a true copy of net.IPNet")
+	}
+}

+ 32 - 7
libnetwork/network.go

@@ -48,8 +48,9 @@ import (
 // NetworkController provides the interface for controller instance which manages
 // networks.
 type NetworkController interface {
+	// NOTE: This method will go away when moving to plugin infrastructure
 	NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error)
-	// Create a new network. The options parameter carry driver specific options.
+	// Create a new network. The options parameter carries network specific options.
 	// Labels support will be added in the near future.
 	NewNetwork(d *NetworkDriver, name string, options interface{}) (Network, error)
 }
@@ -69,7 +70,7 @@ type Network interface {
 	// Create a new endpoint to this network symbolically identified by the
 	// specified unique name. The options parameter carry driver specific options.
 	// Labels support will be added in the near future.
-	CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error)
+	CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error)
 
 	// Delete the network.
 	Delete() error
@@ -77,10 +78,19 @@ type Network interface {
 
 // Endpoint represents a logical connection between a network and a sandbox.
 type Endpoint interface {
-	// A system generated id for this network.
+	// A system generated id for this endpoint.
 	ID() string
 
-	// Delete endpoint.
+	// Name returns the name of this endpoint.
+	Name() string
+
+	// Network returns the name of the network to which this endpoint is attached.
+	Network() string
+
+	// SandboxInfo returns the sandbox information for this endpoint.
+	SandboxInfo() *driverapi.SandboxInfo
+
+	// Delete and detaches this endpoint from the network.
 	Delete() error
 }
 
@@ -222,7 +232,7 @@ func (n *network) Delete() error {
 	return err
 }
 
-func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error) {
+func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error) {
 	ep := &endpoint{name: name}
 	ep.id = driverapi.UUID(stringid.GenerateRandomID())
 	ep.network = n
@@ -230,20 +240,35 @@ func (n *network) CreateEndpoint(name string, sboxKey string, options interface{
 	d := n.driver.internalDriver
 	sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options)
 	if err != nil {
-		return nil, nil, err
+		return nil, err
 	}
 
 	ep.sandboxInfo = sinfo
 	n.Lock()
 	n.endpoints[ep.id] = ep
 	n.Unlock()
-	return ep, sinfo, nil
+	return ep, nil
 }
 
 func (ep *endpoint) ID() string {
 	return string(ep.id)
 }
 
+func (ep *endpoint) Name() string {
+	return ep.name
+}
+
+func (ep *endpoint) Network() string {
+	return ep.network.name
+}
+
+func (ep *endpoint) SandboxInfo() *driverapi.SandboxInfo {
+	if ep.sandboxInfo == nil {
+		return nil
+	}
+	return ep.sandboxInfo.GetCopy()
+}
+
 func (ep *endpoint) Delete() error {
 	var err error
 

+ 2 - 2
libnetwork/sandbox/configure_linux.go

@@ -35,12 +35,12 @@ func setGatewayIP(gw net.IP) error {
 }
 
 func setInterfaceIP(iface netlink.Link, settings *driverapi.Interface) error {
-	ipAddr := &netlink.Addr{IPNet: &settings.Address, Label: ""}
+	ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""}
 	return netlink.AddrAdd(iface, ipAddr)
 }
 
 func setInterfaceIPv6(iface netlink.Link, settings *driverapi.Interface) error {
-	ipAddr := &netlink.Addr{IPNet: &settings.Address, Label: ""}
+	ipAddr := &netlink.Addr{IPNet: settings.Address, Label: ""}
 	return netlink.AddrAdd(iface, ipAddr)
 }