github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration/network/macvlan/macvlan_test.go (about)

     1  // +build !windows
     2  
     3  package macvlan
     4  
     5  import (
     6  	"context"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/docker/docker/client"
    12  	"github.com/docker/docker/integration/internal/container"
    13  	net "github.com/docker/docker/integration/internal/network"
    14  	n "github.com/docker/docker/integration/network"
    15  	"github.com/docker/docker/internal/test/daemon"
    16  	"gotest.tools/assert"
    17  	"gotest.tools/skip"
    18  )
    19  
    20  func TestDockerNetworkMacvlanPersistance(t *testing.T) {
    21  	// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
    22  	skip.If(t, testEnv.IsRemoteDaemon)
    23  	skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
    24  
    25  	d := daemon.New(t)
    26  	d.StartWithBusybox(t)
    27  	defer d.Stop(t)
    28  
    29  	master := "dm-dummy0"
    30  	n.CreateMasterDummy(t, master)
    31  	defer n.DeleteInterface(t, master)
    32  
    33  	c := d.NewClientT(t)
    34  
    35  	netName := "dm-persist"
    36  	net.CreateNoError(t, context.Background(), c, netName,
    37  		net.WithMacvlan("dm-dummy0.60"),
    38  	)
    39  	assert.Check(t, n.IsNetworkAvailable(c, netName))
    40  	d.Restart(t)
    41  	assert.Check(t, n.IsNetworkAvailable(c, netName))
    42  }
    43  
    44  func TestDockerNetworkMacvlan(t *testing.T) {
    45  	skip.If(t, testEnv.IsRemoteDaemon)
    46  	skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
    47  
    48  	for _, tc := range []struct {
    49  		name string
    50  		test func(client.APIClient) func(*testing.T)
    51  	}{
    52  		{
    53  			name: "Subinterface",
    54  			test: testMacvlanSubinterface,
    55  		}, {
    56  			name: "OverlapParent",
    57  			test: testMacvlanOverlapParent,
    58  		}, {
    59  			name: "NilParent",
    60  			test: testMacvlanNilParent,
    61  		}, {
    62  			name: "InternalMode",
    63  			test: testMacvlanInternalMode,
    64  		}, {
    65  			name: "Addressing",
    66  			test: testMacvlanAddressing,
    67  		},
    68  	} {
    69  		d := daemon.New(t)
    70  		d.StartWithBusybox(t)
    71  		c := d.NewClientT(t)
    72  
    73  		t.Run(tc.name, tc.test(c))
    74  
    75  		d.Stop(t)
    76  		// FIXME(vdemeester) clean network
    77  	}
    78  }
    79  
    80  func testMacvlanOverlapParent(client client.APIClient) func(*testing.T) {
    81  	return func(t *testing.T) {
    82  		// verify the same parent interface cannot be used if already in use by an existing network
    83  		master := "dm-dummy0"
    84  		n.CreateMasterDummy(t, master)
    85  		defer n.DeleteInterface(t, master)
    86  
    87  		netName := "dm-subinterface"
    88  		parentName := "dm-dummy0.40"
    89  		net.CreateNoError(t, context.Background(), client, netName,
    90  			net.WithMacvlan(parentName),
    91  		)
    92  		assert.Check(t, n.IsNetworkAvailable(client, netName))
    93  
    94  		_, err := net.Create(context.Background(), client, "dm-parent-net-overlap",
    95  			net.WithMacvlan(parentName),
    96  		)
    97  		assert.Check(t, err != nil)
    98  
    99  		// delete the network while preserving the parent link
   100  		err = client.NetworkRemove(context.Background(), netName)
   101  		assert.NilError(t, err)
   102  
   103  		assert.Check(t, n.IsNetworkNotAvailable(client, netName))
   104  		// verify the network delete did not delete the predefined link
   105  		n.LinkExists(t, master)
   106  	}
   107  }
   108  
   109  func testMacvlanSubinterface(client client.APIClient) func(*testing.T) {
   110  	return func(t *testing.T) {
   111  		// verify the same parent interface cannot be used if already in use by an existing network
   112  		master := "dm-dummy0"
   113  		parentName := "dm-dummy0.20"
   114  		n.CreateMasterDummy(t, master)
   115  		defer n.DeleteInterface(t, master)
   116  		n.CreateVlanInterface(t, master, parentName, "20")
   117  
   118  		netName := "dm-subinterface"
   119  		net.CreateNoError(t, context.Background(), client, netName,
   120  			net.WithMacvlan(parentName),
   121  		)
   122  		assert.Check(t, n.IsNetworkAvailable(client, netName))
   123  
   124  		// delete the network while preserving the parent link
   125  		err := client.NetworkRemove(context.Background(), netName)
   126  		assert.NilError(t, err)
   127  
   128  		assert.Check(t, n.IsNetworkNotAvailable(client, netName))
   129  		// verify the network delete did not delete the predefined link
   130  		n.LinkExists(t, parentName)
   131  	}
   132  }
   133  
   134  func testMacvlanNilParent(client client.APIClient) func(*testing.T) {
   135  	return func(t *testing.T) {
   136  		// macvlan bridge mode - dummy parent interface is provisioned dynamically
   137  		netName := "dm-nil-parent"
   138  		net.CreateNoError(t, context.Background(), client, netName,
   139  			net.WithMacvlan(""),
   140  		)
   141  		assert.Check(t, n.IsNetworkAvailable(client, netName))
   142  
   143  		ctx := context.Background()
   144  		id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
   145  		id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
   146  
   147  		_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
   148  		assert.Check(t, err == nil)
   149  	}
   150  }
   151  
   152  func testMacvlanInternalMode(client client.APIClient) func(*testing.T) {
   153  	return func(t *testing.T) {
   154  		// macvlan bridge mode - dummy parent interface is provisioned dynamically
   155  		netName := "dm-internal"
   156  		net.CreateNoError(t, context.Background(), client, netName,
   157  			net.WithMacvlan(""),
   158  			net.WithInternal(),
   159  		)
   160  		assert.Check(t, n.IsNetworkAvailable(client, netName))
   161  
   162  		ctx := context.Background()
   163  		id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
   164  		id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
   165  
   166  		timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   167  		defer cancel()
   168  		_, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"})
   169  		// FIXME(vdemeester) check the time of error ?
   170  		assert.Check(t, err != nil)
   171  		assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded)
   172  
   173  		_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
   174  		assert.Check(t, err == nil)
   175  	}
   176  }
   177  
   178  func testMacvlanMultiSubnet(client client.APIClient) func(*testing.T) {
   179  	return func(t *testing.T) {
   180  		netName := "dualstackbridge"
   181  		net.CreateNoError(t, context.Background(), client, netName,
   182  			net.WithMacvlan(""),
   183  			net.WithIPv6(),
   184  			net.WithIPAM("172.28.100.0/24", ""),
   185  			net.WithIPAM("172.28.102.0/24", "172.28.102.254"),
   186  			net.WithIPAM("2001:db8:abc2::/64", ""),
   187  			net.WithIPAM("2001:db8:abc4::/64", "2001:db8:abc4::254"),
   188  		)
   189  
   190  		assert.Check(t, n.IsNetworkAvailable(client, netName))
   191  
   192  		// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
   193  		ctx := context.Background()
   194  		id1 := container.Run(t, ctx, client,
   195  			container.WithNetworkMode("dualstackbridge"),
   196  			container.WithIPv4("dualstackbridge", "172.28.100.20"),
   197  			container.WithIPv6("dualstackbridge", "2001:db8:abc2::20"),
   198  		)
   199  		id2 := container.Run(t, ctx, client,
   200  			container.WithNetworkMode("dualstackbridge"),
   201  			container.WithIPv4("dualstackbridge", "172.28.100.21"),
   202  			container.WithIPv6("dualstackbridge", "2001:db8:abc2::21"),
   203  		)
   204  		c1, err := client.ContainerInspect(ctx, id1)
   205  		assert.NilError(t, err)
   206  
   207  		// verify ipv4 connectivity to the explicit --ipv address second to first
   208  		_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].IPAddress})
   209  		assert.NilError(t, err)
   210  		// verify ipv6 connectivity to the explicit --ipv6 address second to first
   211  		_, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address})
   212  		assert.NilError(t, err)
   213  
   214  		// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
   215  		id3 := container.Run(t, ctx, client,
   216  			container.WithNetworkMode("dualstackbridge"),
   217  			container.WithIPv4("dualstackbridge", "172.28.102.20"),
   218  			container.WithIPv6("dualstackbridge", "2001:db8:abc4::20"),
   219  		)
   220  		id4 := container.Run(t, ctx, client,
   221  			container.WithNetworkMode("dualstackbridge"),
   222  			container.WithIPv4("dualstackbridge", "172.28.102.21"),
   223  			container.WithIPv6("dualstackbridge", "2001:db8:abc4::21"),
   224  		)
   225  		c3, err := client.ContainerInspect(ctx, id3)
   226  		assert.NilError(t, err)
   227  
   228  		// verify ipv4 connectivity to the explicit --ipv address from third to fourth
   229  		_, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].IPAddress})
   230  		assert.NilError(t, err)
   231  		// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
   232  		_, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address})
   233  		assert.NilError(t, err)
   234  
   235  		// Inspect the v4 gateway to ensure the proper default GW was assigned
   236  		assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.100.1")
   237  		// Inspect the v6 gateway to ensure the proper default GW was assigned
   238  		assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8:abc2::1")
   239  		// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
   240  		assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.102.254")
   241  		// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
   242  		assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8.abc4::254")
   243  	}
   244  }
   245  
   246  func testMacvlanAddressing(client client.APIClient) func(*testing.T) {
   247  	return func(t *testing.T) {
   248  		// Ensure the default gateways, next-hops and default dev devices are properly set
   249  		netName := "dualstackbridge"
   250  		net.CreateNoError(t, context.Background(), client, netName,
   251  			net.WithMacvlan(""),
   252  			net.WithIPv6(),
   253  			net.WithOption("macvlan_mode", "bridge"),
   254  			net.WithIPAM("172.28.130.0/24", ""),
   255  			net.WithIPAM("2001:db8:abca::/64", "2001:db8:abca::254"),
   256  		)
   257  		assert.Check(t, n.IsNetworkAvailable(client, netName))
   258  
   259  		ctx := context.Background()
   260  		id1 := container.Run(t, ctx, client,
   261  			container.WithNetworkMode("dualstackbridge"),
   262  		)
   263  
   264  		// Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet
   265  		result, err := container.Exec(ctx, client, id1, []string{"ip", "route"})
   266  		assert.NilError(t, err)
   267  		assert.Check(t, strings.Contains(result.Combined(), "default via 172.28.130.1 dev eth0"))
   268  		// Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop
   269  		result, err = container.Exec(ctx, client, id1, []string{"ip", "-6", "route"})
   270  		assert.NilError(t, err)
   271  		assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abca::254 dev eth0"))
   272  	}
   273  }
   274  
   275  // ensure Kernel version is >= v3.9 for macvlan support
   276  func macvlanKernelSupport() bool {
   277  	return n.CheckKernelMajorVersionGreaterOrEqualThen(3, 9)
   278  }