소스 검색

Merge pull request #1508 from aboch/sc

Look for overlap when programming sandbox interface
Jana Radhakrishnan 8 년 전
부모
커밋
bc453b2014
6개의 변경된 파일160개의 추가작업 그리고 40개의 파일을 삭제
  1. 4 4
      libnetwork/endpoint.go
  2. 15 1
      libnetwork/libnetwork_linux_test.go
  3. 29 1
      libnetwork/libnetwork_test.go
  4. 22 1
      libnetwork/osl/interface_linux.go
  5. 64 2
      libnetwork/osl/sandbox_linux_test.go
  6. 26 31
      libnetwork/sandbox_test.go

+ 4 - 4
libnetwork/endpoint.go

@@ -495,10 +495,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 		return err
 	}
 
-	if err = n.getController().updateToStore(ep); err != nil {
-		return err
-	}
-
 	// Current endpoint providing external connectivity for the sandbox
 	extEp := sb.getGatewayEndpoint()
 
@@ -515,6 +511,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
 		return err
 	}
 
+	if err = n.getController().updateToStore(ep); err != nil {
+		return err
+	}
+
 	if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
 		return sb.setupDefaultGW()
 	}

+ 15 - 1
libnetwork/libnetwork_linux_test.go

@@ -402,6 +402,20 @@ func externalKeyTest(t *testing.T, reexec bool) {
 		}
 	}()
 
+	n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
+		netlabel.GenericData: options.Generic{
+			"BridgeName": "testnetwork2",
+		},
+	}, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := n2.Delete(); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
 	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
@@ -413,7 +427,7 @@ func externalKeyTest(t *testing.T, reexec bool) {
 		}
 	}()
 
-	ep2, err := n.CreateEndpoint("ep2")
+	ep2, err := n2.CreateEndpoint("ep2")
 	if err != nil {
 		t.Fatal(err)
 	}

+ 29 - 1
libnetwork/libnetwork_test.go

@@ -882,6 +882,20 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
 		}
 	}()
 
+	n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
+		netlabel.GenericData: options.Generic{
+			"BridgeName": "testnetwork2",
+		},
+	}, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := n2.Delete(); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
 	ep, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
@@ -1012,12 +1026,26 @@ func TestLeaveAll(t *testing.T) {
 		}
 	}()
 
+	n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
+		netlabel.GenericData: options.Generic{
+			"BridgeName": "testnetwork2",
+		},
+	}, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := n2.Delete(); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
 	ep1, err := n.CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	ep2, err := n.CreateEndpoint("ep2")
+	ep2, err := n2.CreateEndpoint("ep2")
 	if err != nil {
 		t.Fatal(err)
 	}

+ 22 - 1
libnetwork/osl/interface_linux.go

@@ -377,7 +377,9 @@ func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
 	if i.Address() == nil {
 		return nil
 	}
-
+	if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
+		return err
+	}
 	ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
 	return nlh.AddrAdd(iface, ipAddr)
 }
@@ -386,6 +388,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
 	if i.AddressIPv6() == nil {
 		return nil
 	}
+	if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
+		return err
+	}
 	ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
 	return nlh.AddrAdd(iface, ipAddr)
 }
@@ -442,3 +447,19 @@ func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error
 
 	return err
 }
+
+func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
+	routes, err := nlh.RouteList(nil, family)
+	if err != nil {
+		return err
+	}
+	for _, route := range routes {
+		if route.Dst != nil {
+			if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) {
+				return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s",
+					address, route)
+			}
+		}
+	}
+	return nil
+}

+ 64 - 2
libnetwork/osl/sandbox_linux_test.go

@@ -7,6 +7,7 @@ import (
 	"net"
 	"os"
 	"path/filepath"
+	"strings"
 	"syscall"
 	"testing"
 	"time"
@@ -74,8 +75,7 @@ func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) {
 	intf1.address = addr
 	intf1.address.IP = ip4
 
-	// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
-	ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
+	ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
 	if err != nil {
 		return nil, err
 	}
@@ -225,3 +225,65 @@ func TestDisableIPv6DAD(t *testing.T) {
 		t.Fatalf("Unexpected interface flags: 0x%x. Expected to contain 0x%x", addrList[0].Flags, syscall.IFA_F_NODAD)
 	}
 }
+
+func TestSetInterfaceIP(t *testing.T) {
+	defer testutils.SetupTestOSContext(t)()
+
+	ipv4, _ := types.ParseCIDR("172.30.0.33/24")
+	ipv6, _ := types.ParseCIDR("2001:db8::44/64")
+	iface := &nwIface{address: ipv4, addressIPv6: ipv6}
+
+	nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := nlh.LinkAdd(&netlink.Veth{
+		LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
+		PeerName:  "sideB",
+	}); err != nil {
+		t.Fatal(err)
+	}
+
+	linkA, err := nlh.LinkByName("sideA")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	linkB, err := nlh.LinkByName("sideB")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := nlh.LinkSetUp(linkA); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := nlh.LinkSetUp(linkB); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := setInterfaceIP(nlh, linkA, iface); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := setInterfaceIPv6(nlh, linkA, iface); err != nil {
+		t.Fatal(err)
+	}
+
+	err = setInterfaceIP(nlh, linkB, iface)
+	if err == nil {
+		t.Fatalf("Expected route conflict error, but succeeded")
+	}
+	if !strings.Contains(err.Error(), "conflicts with existing route") {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	err = setInterfaceIPv6(nlh, linkB, iface)
+	if err == nil {
+		t.Fatalf("Expected route conflict error, but succeeded")
+	}
+	if !strings.Contains(err.Error(), "conflicts with existing route") {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+}

+ 26 - 31
libnetwork/sandbox_test.go

@@ -1,6 +1,7 @@
 package libnetwork
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/docker/libnetwork/config"
@@ -10,7 +11,7 @@ import (
 	"github.com/docker/libnetwork/testutils"
 )
 
-func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network) {
+func getTestEnv(t *testing.T, numNetworks int) (NetworkController, []Network) {
 	netType := "bridge"
 
 	option := options.Generic{
@@ -28,37 +29,31 @@ func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network)
 		t.Fatal(err)
 	}
 
-	if empty {
-		return c, nil, nil
+	if numNetworks == 0 {
+		return c, nil
 	}
 
-	name1 := "test_nw_1"
-	netOption1 := options.Generic{
-		netlabel.GenericData: options.Generic{
-			"BridgeName": name1,
-		},
-	}
-	n1, err := c.NewNetwork(netType, name1, "", NetworkOptionGeneric(netOption1))
-	if err != nil {
-		t.Fatal(err)
-	}
+	nwList := make([]Network, 0, numNetworks)
+	for i := 0; i < numNetworks; i++ {
+		name := fmt.Sprintf("test_nw_%d", i)
+		netOption := options.Generic{
+			netlabel.GenericData: options.Generic{
+				"BridgeName": name,
+			},
+		}
+		n, err := c.NewNetwork(netType, name, "", NetworkOptionGeneric(netOption))
+		if err != nil {
+			t.Fatal(err)
+		}
 
-	name2 := "test_nw_2"
-	netOption2 := options.Generic{
-		netlabel.GenericData: options.Generic{
-			"BridgeName": name2,
-		},
-	}
-	n2, err := c.NewNetwork(netType, name2, "", NetworkOptionGeneric(netOption2))
-	if err != nil {
-		t.Fatal(err)
+		nwList = append(nwList, n)
 	}
 
-	return c, n1, n2
+	return c, nwList
 }
 
 func TestSandboxAddEmpty(t *testing.T) {
-	c, _, _ := getTestEnv(t, true)
+	c, _ := getTestEnv(t, 0)
 	ctrlr := c.(*controller)
 
 	sbx, err := ctrlr.NewSandbox("sandbox0")
@@ -82,7 +77,7 @@ func TestSandboxAddMultiPrio(t *testing.T) {
 		defer testutils.SetupTestOSContext(t)()
 	}
 
-	c, nw, _ := getTestEnv(t, false)
+	c, nws := getTestEnv(t, 3)
 	ctrlr := c.(*controller)
 
 	sbx, err := ctrlr.NewSandbox("sandbox1")
@@ -91,15 +86,15 @@ func TestSandboxAddMultiPrio(t *testing.T) {
 	}
 	sid := sbx.ID()
 
-	ep1, err := nw.CreateEndpoint("ep1")
+	ep1, err := nws[0].CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep2, err := nw.CreateEndpoint("ep2")
+	ep2, err := nws[1].CreateEndpoint("ep2")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep3, err := nw.CreateEndpoint("ep3")
+	ep3, err := nws[2].CreateEndpoint("ep3")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -163,7 +158,7 @@ func TestSandboxAddSamePrio(t *testing.T) {
 		defer testutils.SetupTestOSContext(t)()
 	}
 
-	c, nw1, nw2 := getTestEnv(t, false)
+	c, nws := getTestEnv(t, 2)
 
 	ctrlr := c.(*controller)
 
@@ -173,11 +168,11 @@ func TestSandboxAddSamePrio(t *testing.T) {
 	}
 	sid := sbx.ID()
 
-	ep1, err := nw1.CreateEndpoint("ep1")
+	ep1, err := nws[0].CreateEndpoint("ep1")
 	if err != nil {
 		t.Fatal(err)
 	}
-	ep2, err := nw2.CreateEndpoint("ep2")
+	ep2, err := nws[1].CreateEndpoint("ep2")
 	if err != nil {
 		t.Fatal(err)
 	}