github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/integration/network/macvlan/macvlan_test.go (about)

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