123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- 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)
- ctr1MacAddress string
- 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"),
- },
- // Link-local address is derived from the MAC address, so we need to
- // specify one here to hardcode the SLAAC LL address below.
- ctr1MacAddress: "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"),
- },
- // Link-local address is derived from the MAC address, so we need to
- // specify one here to hardcode the SLAAC LL address below.
- ctr1MacAddress: "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)
- var ctr1Opts []func(config *container.TestContainerConfig)
- if tc.ctr1MacAddress != "" {
- ctr1Opts = append(ctr1Opts, container.WithMacAddress(bridgeName, tc.ctr1MacAddress))
- }
- id1 := container.Run(ctx, t, c, append(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))
- })
- }
- }
|