Procházet zdrojové kódy

integration/networking: Test bridge ICC and INC

Following tests are implemented in this specific commit:

- Inter-container communications for internal and non-internal
  bridge networks, over IPv4 and IPv6.
- Inter-container communications using IPv6 link-local addresses for
  internal and non-internal bridge networks.
- Inter-network communications for internal and non-internal bridge
  networks, over IPv4 and IPv6, are disallowed.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Albin Kerouanton před 2 roky
rodič
revize
c1ab6eda4b
1 změnil soubory, kde provedl 294 přidání a 0 odebrání
  1. 294 0
      integration/networking/bridge_test.go

+ 294 - 0
integration/networking/bridge_test.go

@@ -0,0 +1,294 @@
+package networking
+
+import (
+	"context"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/integration/internal/network"
+	"github.com/docker/docker/testutil"
+	"github.com/docker/docker/testutil/daemon"
+	"gotest.tools/v3/assert"
+	is "gotest.tools/v3/assert/cmp"
+	"gotest.tools/v3/skip"
+)
+
+// TestBridgeICC tries to ping container ctr1 from container ctr2 using its hostname. Thus, this test checks:
+// 1. DNS resolution ; 2. ARP/NDP ; 3. whether containers can communicate with each other ; 4. kernel-assigned SLAAC
+// addresses.
+func TestBridgeICC(t *testing.T) {
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
+
+	ctx := setupTest(t)
+
+	d := daemon.New(t)
+	d.StartWithBusybox(ctx, t, "-D", "--experimental", "--ip6tables")
+	defer d.Stop(t)
+
+	c := d.NewClientT(t)
+	defer c.Close()
+
+	testcases := []struct {
+		name       string
+		bridgeOpts []func(*types.NetworkCreate)
+		ctr1Opts   []func(*container.TestContainerConfig)
+		linkLocal  bool
+		pingHost   string
+	}{
+		{
+			name:       "IPv4 non-internal network",
+			bridgeOpts: []func(*types.NetworkCreate){},
+		},
+		{
+			name: "IPv4 internal network",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithInternal(),
+			},
+		},
+		{
+			name: "IPv6 ULA on non-internal network",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				network.WithIPAM("fdf1:a844:380c:b200::/64", "fdf1:a844:380c:b200::1"),
+			},
+		},
+		{
+			name: "IPv6 ULA on internal network",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				network.WithInternal(),
+				network.WithIPAM("fdf1:a844:380c:b247::/64", "fdf1:a844:380c:b247::1"),
+			},
+		},
+		{
+			name: "IPv6 link-local address on non-internal network",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				// There's no real way to specify an IPv6 network is only used with SLAAC link-local IPv6 addresses.
+				// What we can do instead, is to tell the IPAM driver to assign addresses from the link-local prefix.
+				// Each container will have two link-local addresses: 1. a SLAAC address assigned by the kernel ;
+				// 2. the one dynamically assigned by the IPAM driver.
+				network.WithIPAM("fe80::/64", "fe80::1"),
+			},
+			linkLocal: true,
+		},
+		{
+			name: "IPv6 link-local address on internal network",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				network.WithInternal(),
+				// See the note above about link-local addresses.
+				network.WithIPAM("fe80::/64", "fe80::1"),
+			},
+			linkLocal: true,
+		},
+		{
+			name: "IPv6 non-internal network with SLAAC LL address",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				network.WithIPAM("fdf1:a844:380c:b247::/64", "fdf1:a844:380c:b247::1"),
+			},
+			ctr1Opts: []func(*container.TestContainerConfig){
+				// Link-local address is derived from the MAC address, so we need to
+				// specify one here to hardcode the SLAAC LL address below.
+				container.WithMacAddress("02:42:ac:11:00:02"),
+			},
+			pingHost: "fe80::42:acff:fe11:2%eth0",
+		},
+		{
+			name: "IPv6 internal network with SLAAC LL address",
+			bridgeOpts: []func(*types.NetworkCreate){
+				network.WithIPv6(),
+				network.WithIPAM("fdf1:a844:380c:b247::/64", "fdf1:a844:380c:b247::1"),
+			},
+			ctr1Opts: []func(*container.TestContainerConfig){
+				// Link-local address is derived from the MAC address, so we need to
+				// specify one here to hardcode the SLAAC LL address below.
+				container.WithMacAddress("02:42:ac:11:00:02"),
+			},
+			pingHost: "fe80::42:acff:fe11:2%eth0",
+		},
+	}
+
+	for tcID, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := testutil.StartSpan(ctx, t)
+
+			bridgeName := fmt.Sprintf("testnet-icc-%d", tcID)
+			network.CreateNoError(ctx, t, c, bridgeName, append(tc.bridgeOpts,
+				network.WithDriver("bridge"),
+				network.WithOption("com.docker.network.bridge.name", bridgeName))...)
+			defer network.RemoveNoError(ctx, t, c, bridgeName)
+
+			ctr1Name := fmt.Sprintf("ctr-icc-%d-1", tcID)
+			id1 := container.Run(ctx, t, c, append(tc.ctr1Opts,
+				container.WithName(ctr1Name),
+				container.WithImage("busybox:latest"),
+				container.WithCmd("top"),
+				container.WithNetworkMode(bridgeName))...)
+			defer c.ContainerRemove(ctx, id1, containertypes.RemoveOptions{
+				Force: true,
+			})
+
+			pingHost := tc.pingHost
+			if pingHost == "" {
+				if tc.linkLocal {
+					inspect := container.Inspect(ctx, t, c, id1)
+					pingHost = inspect.NetworkSettings.Networks[bridgeName].GlobalIPv6Address + "%eth0"
+				} else {
+					pingHost = ctr1Name
+				}
+			}
+
+			pingCmd := []string{"ping", "-c1", "-W3", pingHost}
+
+			ctr2Name := fmt.Sprintf("ctr-icc-%d-2", tcID)
+			attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+			defer cancel()
+			res := container.RunAttach(attachCtx, t, c,
+				container.WithName(ctr2Name),
+				container.WithImage("busybox:latest"),
+				container.WithCmd(pingCmd...),
+				container.WithNetworkMode(bridgeName))
+			defer c.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{
+				Force: true,
+			})
+
+			assert.Check(t, is.Equal(res.ExitCode, 0))
+			assert.Check(t, is.Equal(res.Stderr.Len(), 0))
+			assert.Check(t, is.Contains(res.Stdout.String(), "1 packets transmitted, 1 packets received"))
+		})
+	}
+}
+
+// TestBridgeINC makes sure two containers on two different bridge networks can't communicate with each other.
+func TestBridgeINC(t *testing.T) {
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
+
+	ctx := setupTest(t)
+
+	d := daemon.New(t)
+	d.StartWithBusybox(ctx, t, "-D", "--experimental", "--ip6tables")
+	defer d.Stop(t)
+
+	c := d.NewClientT(t)
+	defer c.Close()
+
+	type bridgesOpts struct {
+		bridge1Opts []func(*types.NetworkCreate)
+		bridge2Opts []func(*types.NetworkCreate)
+	}
+
+	testcases := []struct {
+		name    string
+		bridges bridgesOpts
+		ipv6    bool
+		stdout  string
+		stderr  string
+	}{
+		{
+			name: "IPv4 non-internal network",
+			bridges: bridgesOpts{
+				bridge1Opts: []func(*types.NetworkCreate){},
+				bridge2Opts: []func(*types.NetworkCreate){},
+			},
+			stdout: "1 packets transmitted, 0 packets received",
+		},
+		{
+			name: "IPv4 internal network",
+			bridges: bridgesOpts{
+				bridge1Opts: []func(*types.NetworkCreate){network.WithInternal()},
+				bridge2Opts: []func(*types.NetworkCreate){network.WithInternal()},
+			},
+			stderr: "sendto: Network is unreachable",
+		},
+		{
+			name: "IPv6 ULA on non-internal network",
+			bridges: bridgesOpts{
+				bridge1Opts: []func(*types.NetworkCreate){
+					network.WithIPv6(),
+					network.WithIPAM("fdf1:a844:380c:b200::/64", "fdf1:a844:380c:b200::1"),
+				},
+				bridge2Opts: []func(*types.NetworkCreate){
+					network.WithIPv6(),
+					network.WithIPAM("fdf1:a844:380c:b247::/64", "fdf1:a844:380c:b247::1"),
+				},
+			},
+			ipv6:   true,
+			stdout: "1 packets transmitted, 0 packets received",
+		},
+		{
+			name: "IPv6 ULA on internal network",
+			bridges: bridgesOpts{
+				bridge1Opts: []func(*types.NetworkCreate){
+					network.WithIPv6(),
+					network.WithInternal(),
+					network.WithIPAM("fdf1:a844:390c:b200::/64", "fdf1:a844:390c:b200::1"),
+				},
+				bridge2Opts: []func(*types.NetworkCreate){
+					network.WithIPv6(),
+					network.WithInternal(),
+					network.WithIPAM("fdf1:a844:390c:b247::/64", "fdf1:a844:390c:b247::1"),
+				},
+			},
+			ipv6:   true,
+			stderr: "sendto: Network is unreachable",
+		},
+	}
+
+	for tcID, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := testutil.StartSpan(ctx, t)
+
+			bridge1 := fmt.Sprintf("testnet-inc-%d-1", tcID)
+			bridge2 := fmt.Sprintf("testnet-inc-%d-2", tcID)
+
+			network.CreateNoError(ctx, t, c, bridge1, append(tc.bridges.bridge1Opts,
+				network.WithDriver("bridge"),
+				network.WithOption("com.docker.network.bridge.name", bridge1))...)
+			defer network.RemoveNoError(ctx, t, c, bridge1)
+			network.CreateNoError(ctx, t, c, bridge2, append(tc.bridges.bridge2Opts,
+				network.WithDriver("bridge"),
+				network.WithOption("com.docker.network.bridge.name", bridge2))...)
+			defer network.RemoveNoError(ctx, t, c, bridge2)
+
+			ctr1Name := sanitizeCtrName(t.Name() + "-ctr1")
+			id1 := container.Run(ctx, t, c,
+				container.WithName(ctr1Name),
+				container.WithImage("busybox:latest"),
+				container.WithCmd("top"),
+				container.WithNetworkMode(bridge1))
+			defer c.ContainerRemove(ctx, id1, containertypes.RemoveOptions{
+				Force: true,
+			})
+
+			ctr1Info := container.Inspect(ctx, t, c, id1)
+			targetAddr := ctr1Info.NetworkSettings.Networks[bridge1].IPAddress
+			if tc.ipv6 {
+				targetAddr = ctr1Info.NetworkSettings.Networks[bridge1].GlobalIPv6Address
+			}
+
+			pingCmd := []string{"ping", "-c1", "-W3", targetAddr}
+
+			ctr2Name := sanitizeCtrName(t.Name() + "-ctr2")
+			attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+			defer cancel()
+			res := container.RunAttach(attachCtx, t, c,
+				container.WithName(ctr2Name),
+				container.WithImage("busybox:latest"),
+				container.WithCmd(pingCmd...),
+				container.WithNetworkMode(bridge2))
+			defer c.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{
+				Force: true,
+			})
+
+			assert.Check(t, res.ExitCode != 0, "ping unexpectedly succeeded")
+			assert.Check(t, is.Contains(res.Stdout.String(), tc.stdout))
+			assert.Check(t, is.Contains(res.Stderr.String(), tc.stderr))
+		})
+	}
+}