github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/integration-cli/docker_cli_network_unix_test.go (about)

     1  //go:build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"fmt"
     9  	"net"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"os"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/docker/docker/api/types"
    18  	"github.com/docker/docker/integration-cli/cli"
    19  	"github.com/docker/docker/integration-cli/daemon"
    20  	"github.com/docker/docker/libnetwork/driverapi"
    21  	remoteapi "github.com/docker/docker/libnetwork/drivers/remote/api"
    22  	"github.com/docker/docker/libnetwork/ipamapi"
    23  	remoteipam "github.com/docker/docker/libnetwork/ipams/remote/api"
    24  	"github.com/docker/docker/libnetwork/netlabel"
    25  	"github.com/docker/docker/pkg/plugins"
    26  	"github.com/docker/docker/pkg/stringid"
    27  	"github.com/docker/docker/runconfig"
    28  	"github.com/docker/docker/testutil"
    29  	testdaemon "github.com/docker/docker/testutil/daemon"
    30  	"github.com/vishvananda/netlink"
    31  	"golang.org/x/sys/unix"
    32  	"gotest.tools/v3/assert"
    33  	is "gotest.tools/v3/assert/cmp"
    34  	"gotest.tools/v3/icmd"
    35  )
    36  
    37  const (
    38  	dummyNetworkDriver = "dummy-network-driver"
    39  	dummyIPAMDriver    = "dummy-ipam-driver"
    40  )
    41  
    42  var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
    43  
    44  func (s *DockerNetworkSuite) SetUpTest(ctx context.Context, c *testing.T) {
    45  	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
    46  }
    47  
    48  func (s *DockerNetworkSuite) TearDownTest(ctx context.Context, c *testing.T) {
    49  	if s.d != nil {
    50  		s.d.Stop(c)
    51  		s.ds.TearDownTest(ctx, c)
    52  	}
    53  }
    54  
    55  func (s *DockerNetworkSuite) SetUpSuite(ctx context.Context, c *testing.T) {
    56  	mux := http.NewServeMux()
    57  	s.server = httptest.NewServer(mux)
    58  	assert.Assert(c, s.server != nil, "Failed to start an HTTP Server")
    59  	setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver)
    60  }
    61  
    62  func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
    63  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
    64  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    65  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
    66  	})
    67  
    68  	// Network driver implementation
    69  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    70  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    71  		fmt.Fprintf(w, `{"Scope":"local"}`)
    72  	})
    73  
    74  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    75  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
    76  		if err != nil {
    77  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
    78  			return
    79  		}
    80  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    81  		fmt.Fprintf(w, "null")
    82  	})
    83  
    84  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    85  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    86  		fmt.Fprintf(w, "null")
    87  	})
    88  
    89  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    90  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    91  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
    92  	})
    93  
    94  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    95  		w.Header().Set("Content-Type", plugins.VersionMimetype)
    96  
    97  		veth := &netlink.Veth{
    98  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0",
    99  		}
   100  		if err := netlink.LinkAdd(veth); err != nil {
   101  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   102  		} else {
   103  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   104  		}
   105  	})
   106  
   107  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   108  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   109  		fmt.Fprintf(w, "null")
   110  	})
   111  
   112  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   113  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   114  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   115  			netlink.LinkDel(link)
   116  		}
   117  		fmt.Fprintf(w, "null")
   118  	})
   119  
   120  	// IPAM Driver implementation
   121  	var (
   122  		poolRequest       remoteipam.RequestPoolRequest
   123  		poolReleaseReq    remoteipam.ReleasePoolRequest
   124  		addressRequest    remoteipam.RequestAddressRequest
   125  		addressReleaseReq remoteipam.ReleaseAddressRequest
   126  		lAS               = "localAS"
   127  		gAS               = "globalAS"
   128  		pool              = "172.28.0.0/16"
   129  		poolID            = lAS + "/" + pool
   130  		gw                = "172.28.255.254/16"
   131  	)
   132  
   133  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   134  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   135  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   136  	})
   137  
   138  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   139  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   140  		if err != nil {
   141  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   142  			return
   143  		}
   144  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   145  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   146  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   147  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   148  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   149  		} else {
   150  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   151  		}
   152  	})
   153  
   154  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   155  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   156  		if err != nil {
   157  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   158  			return
   159  		}
   160  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   161  		// make sure libnetwork is now querying on the expected pool id
   162  		if addressRequest.PoolID != poolID {
   163  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   164  		} else if addressRequest.Address != "" {
   165  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   166  		} else {
   167  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   168  		}
   169  	})
   170  
   171  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   172  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   173  		if err != nil {
   174  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   175  			return
   176  		}
   177  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   178  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   179  		if addressRequest.PoolID != poolID {
   180  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   181  		} else if addressReleaseReq.Address != gw {
   182  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   183  		} else {
   184  			fmt.Fprintf(w, "null")
   185  		}
   186  	})
   187  
   188  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   189  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   190  		if err != nil {
   191  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   192  			return
   193  		}
   194  		w.Header().Set("Content-Type", plugins.VersionMimetype)
   195  		// make sure libnetwork is now asking to release the expected poolid
   196  		if addressRequest.PoolID != poolID {
   197  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   198  		} else {
   199  			fmt.Fprintf(w, "null")
   200  		}
   201  	})
   202  
   203  	err := os.MkdirAll("/etc/docker/plugins", 0o755)
   204  	assert.NilError(c, err)
   205  
   206  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   207  	err = os.WriteFile(fileName, []byte(url), 0o644)
   208  	assert.NilError(c, err)
   209  
   210  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   211  	err = os.WriteFile(ipamFileName, []byte(url), 0o644)
   212  	assert.NilError(c, err)
   213  }
   214  
   215  func (s *DockerNetworkSuite) TearDownSuite(ctx context.Context, c *testing.T) {
   216  	if s.server == nil {
   217  		return
   218  	}
   219  
   220  	s.server.Close()
   221  
   222  	err := os.RemoveAll("/etc/docker/plugins")
   223  	assert.NilError(c, err)
   224  }
   225  
   226  func assertNwIsAvailable(c *testing.T, name string) {
   227  	if !isNwPresent(c, name) {
   228  		c.Fatalf("Network %s not found in network ls o/p", name)
   229  	}
   230  }
   231  
   232  func assertNwNotAvailable(c *testing.T, name string) {
   233  	if isNwPresent(c, name) {
   234  		c.Fatalf("Found network %s in network ls o/p", name)
   235  	}
   236  }
   237  
   238  func isNwPresent(c *testing.T, name string) bool {
   239  	out := cli.DockerCmd(c, "network", "ls").Stdout()
   240  	lines := strings.Split(out, "\n")
   241  	for i := 1; i < len(lines)-1; i++ {
   242  		netFields := strings.Fields(lines[i])
   243  		if netFields[1] == name {
   244  			return true
   245  		}
   246  	}
   247  	return false
   248  }
   249  
   250  // assertNwList checks network list retrieved with ls command
   251  // equals to expected network list
   252  // note: out should be `network ls [option]` result
   253  func assertNwList(c *testing.T, out string, expectNws []string) {
   254  	lines := strings.Split(out, "\n")
   255  	var nwList []string
   256  	for _, line := range lines[1 : len(lines)-1] {
   257  		netFields := strings.Fields(line)
   258  		// wrap all network name in nwList
   259  		nwList = append(nwList, netFields[1])
   260  	}
   261  
   262  	// network ls should contains all expected networks
   263  	assert.DeepEqual(c, nwList, expectNws)
   264  }
   265  
   266  func getNwResource(c *testing.T, name string) *types.NetworkResource {
   267  	out := cli.DockerCmd(c, "network", "inspect", name).Stdout()
   268  	var nr []types.NetworkResource
   269  	err := json.Unmarshal([]byte(out), &nr)
   270  	assert.NilError(c, err)
   271  	return &nr[0]
   272  }
   273  
   274  func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *testing.T) {
   275  	defaults := []string{"bridge", "host", "none"}
   276  	for _, nn := range defaults {
   277  		assertNwIsAvailable(c, nn)
   278  	}
   279  }
   280  
   281  func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *testing.T) {
   282  	predefined := []string{"bridge", "host", "none", "default"}
   283  	for _, nw := range predefined {
   284  		// predefined networks can't be created again
   285  		out, _, err := dockerCmdWithError("network", "create", nw)
   286  		assert.ErrorContains(c, err, "", out)
   287  	}
   288  }
   289  
   290  func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *testing.T) {
   291  	cli.DockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
   292  	assertNwIsAvailable(c, "testbind")
   293  
   294  	id := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000")
   295  	cli.WaitRun(c, id)
   296  	out := cli.DockerCmd(c, "ps").Stdout()
   297  	assert.Assert(c, strings.Contains(out, "192.168.10.1:5000->5000/tcp"))
   298  }
   299  
   300  func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *testing.T) {
   301  	predefined := []string{"bridge", "host", "none", "default"}
   302  	for _, nw := range predefined {
   303  		// predefined networks can't be removed
   304  		out, _, err := dockerCmdWithError("network", "rm", nw)
   305  		assert.ErrorContains(c, err, "", out)
   306  	}
   307  }
   308  
   309  func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *testing.T) {
   310  	testRequires(c, func() bool { return OnlyDefaultNetworks(testutil.GetContext(c)) })
   311  
   312  	testNet := "testnet1"
   313  	testLabel := "foo"
   314  	testValue := "bar"
   315  	out := cli.DockerCmd(c, "network", "create", "dev").Stdout()
   316  	defer func() {
   317  		cli.DockerCmd(c, "network", "rm", "dev")
   318  		cli.DockerCmd(c, "network", "rm", testNet)
   319  	}()
   320  	networkID := strings.TrimSpace(out)
   321  
   322  	// filter with partial ID
   323  	// only show 'dev' network
   324  	out = cli.DockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5]).Stdout()
   325  	assertNwList(c, out, []string{"dev"})
   326  
   327  	out = cli.DockerCmd(c, "network", "ls", "-f", "name=dge").Stdout()
   328  	assertNwList(c, out, []string{"bridge"})
   329  
   330  	// only show built-in network (bridge, none, host)
   331  	out = cli.DockerCmd(c, "network", "ls", "-f", "type=builtin").Stdout()
   332  	assertNwList(c, out, []string{"bridge", "host", "none"})
   333  
   334  	// only show custom networks (dev)
   335  	out = cli.DockerCmd(c, "network", "ls", "-f", "type=custom").Stdout()
   336  	assertNwList(c, out, []string{"dev"})
   337  
   338  	// show all networks with filter
   339  	// it should be equivalent of ls without option
   340  	out = cli.DockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin").Stdout()
   341  	assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
   342  
   343  	cli.DockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
   344  	assertNwIsAvailable(c, testNet)
   345  
   346  	out = cli.DockerCmd(c, "network", "ls", "-f", "label="+testLabel).Stdout()
   347  	assertNwList(c, out, []string{testNet})
   348  
   349  	out = cli.DockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue).Stdout()
   350  	assertNwList(c, out, []string{testNet})
   351  
   352  	out = cli.DockerCmd(c, "network", "ls", "-f", "label=nonexistent").Stdout()
   353  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   354  	assert.Equal(c, len(outArr), 1, fmt.Sprintf("%s\n", out))
   355  
   356  	out = cli.DockerCmd(c, "network", "ls", "-f", "driver=null").Stdout()
   357  	assertNwList(c, out, []string{"none"})
   358  
   359  	out = cli.DockerCmd(c, "network", "ls", "-f", "driver=host").Stdout()
   360  	assertNwList(c, out, []string{"host"})
   361  
   362  	out = cli.DockerCmd(c, "network", "ls", "-f", "driver=bridge").Stdout()
   363  	assertNwList(c, out, []string{"bridge", "dev", testNet})
   364  }
   365  
   366  func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *testing.T) {
   367  	cli.DockerCmd(c, "network", "create", "test")
   368  	assertNwIsAvailable(c, "test")
   369  
   370  	cli.DockerCmd(c, "network", "rm", "test")
   371  	assertNwNotAvailable(c, "test")
   372  }
   373  
   374  func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *testing.T) {
   375  	testNet := "testnetcreatelabel"
   376  	testLabel := "foo"
   377  	testValue := "bar"
   378  
   379  	cli.DockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
   380  	assertNwIsAvailable(c, testNet)
   381  
   382  	out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet)
   383  	assert.NilError(c, err)
   384  	assert.Equal(c, strings.TrimSpace(out), testValue)
   385  
   386  	cli.DockerCmd(c, "network", "rm", testNet)
   387  	assertNwNotAvailable(c, testNet)
   388  }
   389  
   390  func (s *DockerCLINetworkSuite) TestDockerNetworkDeleteNotExists(c *testing.T) {
   391  	out, _, err := dockerCmdWithError("network", "rm", "test")
   392  	assert.ErrorContains(c, err, "", out)
   393  }
   394  
   395  func (s *DockerCLINetworkSuite) TestDockerNetworkDeleteMultiple(c *testing.T) {
   396  	cli.DockerCmd(c, "network", "create", "testDelMulti0")
   397  	assertNwIsAvailable(c, "testDelMulti0")
   398  	cli.DockerCmd(c, "network", "create", "testDelMulti1")
   399  	assertNwIsAvailable(c, "testDelMulti1")
   400  	cli.DockerCmd(c, "network", "create", "testDelMulti2")
   401  	assertNwIsAvailable(c, "testDelMulti2")
   402  	out := cli.DockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top").Stdout()
   403  	containerID := strings.TrimSpace(out)
   404  	cli.WaitRun(c, containerID)
   405  
   406  	// delete three networks at the same time, since testDelMulti2
   407  	// contains active container, its deletion should fail.
   408  	out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2")
   409  	// err should not be nil due to deleting testDelMulti2 failed.
   410  	assert.Assert(c, err != nil, "out: %s", out)
   411  	// testDelMulti2 should fail due to network has active endpoints
   412  	assert.Assert(c, strings.Contains(out, "has active endpoints"))
   413  	assertNwNotAvailable(c, "testDelMulti0")
   414  	assertNwNotAvailable(c, "testDelMulti1")
   415  	// testDelMulti2 can't be deleted, so it should exist
   416  	assertNwIsAvailable(c, "testDelMulti2")
   417  }
   418  
   419  func (s *DockerCLINetworkSuite) TestDockerNetworkInspect(c *testing.T) {
   420  	out := cli.DockerCmd(c, "network", "inspect", "host").Stdout()
   421  	var networkResources []types.NetworkResource
   422  	err := json.Unmarshal([]byte(out), &networkResources)
   423  	assert.NilError(c, err)
   424  	assert.Equal(c, len(networkResources), 1)
   425  
   426  	out = cli.DockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host").Stdout()
   427  	assert.Equal(c, strings.TrimSpace(out), "host")
   428  }
   429  
   430  func (s *DockerCLINetworkSuite) TestDockerNetworkInspectWithID(c *testing.T) {
   431  	out := cli.DockerCmd(c, "network", "create", "test2").Stdout()
   432  	networkID := strings.TrimSpace(out)
   433  	assertNwIsAvailable(c, "test2")
   434  	out = cli.DockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2").Stdout()
   435  	assert.Equal(c, strings.TrimSpace(out), networkID)
   436  
   437  	out = cli.DockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2").Stdout()
   438  	assert.Equal(c, strings.TrimSpace(out), networkID)
   439  }
   440  
   441  func (s *DockerCLINetworkSuite) TestDockerInspectMultipleNetwork(c *testing.T) {
   442  	result := dockerCmdWithResult("network", "inspect", "host", "none")
   443  	result.Assert(c, icmd.Success)
   444  
   445  	var networkResources []types.NetworkResource
   446  	err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
   447  	assert.NilError(c, err)
   448  	assert.Equal(c, len(networkResources), 2)
   449  }
   450  
   451  func (s *DockerCLINetworkSuite) TestDockerInspectMultipleNetworksIncludingNonexistent(c *testing.T) {
   452  	// non-existent network was not at the beginning of the inspect list
   453  	// This should print an error, return an exitCode 1 and print the host network
   454  	result := dockerCmdWithResult("network", "inspect", "host", "nonexistent")
   455  	result.Assert(c, icmd.Expected{
   456  		ExitCode: 1,
   457  		Err:      "Error: No such network: nonexistent",
   458  		Out:      "host",
   459  	})
   460  
   461  	var networkResources []types.NetworkResource
   462  	err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
   463  	assert.NilError(c, err)
   464  	assert.Equal(c, len(networkResources), 1)
   465  
   466  	// Only one non-existent network to inspect
   467  	// Should print an error and return an exitCode, nothing else
   468  	result = dockerCmdWithResult("network", "inspect", "nonexistent")
   469  	result.Assert(c, icmd.Expected{
   470  		ExitCode: 1,
   471  		Err:      "Error: No such network: nonexistent",
   472  		Out:      "[]",
   473  	})
   474  
   475  	// non-existent network was at the beginning of the inspect list
   476  	// Should not fail fast, and still print host network but print an error
   477  	result = dockerCmdWithResult("network", "inspect", "nonexistent", "host")
   478  	result.Assert(c, icmd.Expected{
   479  		ExitCode: 1,
   480  		Err:      "Error: No such network: nonexistent",
   481  		Out:      "host",
   482  	})
   483  
   484  	networkResources = []types.NetworkResource{}
   485  	err = json.Unmarshal([]byte(result.Stdout()), &networkResources)
   486  	assert.NilError(c, err)
   487  	assert.Equal(c, len(networkResources), 1)
   488  }
   489  
   490  func (s *DockerCLINetworkSuite) TestDockerInspectNetworkWithContainerName(c *testing.T) {
   491  	cli.DockerCmd(c, "network", "create", "brNetForInspect")
   492  	assertNwIsAvailable(c, "brNetForInspect")
   493  	defer func() {
   494  		cli.DockerCmd(c, "network", "rm", "brNetForInspect")
   495  		assertNwNotAvailable(c, "brNetForInspect")
   496  	}()
   497  
   498  	out := cli.DockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top").Stdout()
   499  	cli.WaitRun(c, "testNetInspect1")
   500  	containerID := strings.TrimSpace(out)
   501  	defer func() {
   502  		// we don't stop container by name, because we'll rename it later
   503  		cli.DockerCmd(c, "stop", containerID)
   504  	}()
   505  
   506  	out = cli.DockerCmd(c, "network", "inspect", "brNetForInspect").Stdout()
   507  	var networkResources []types.NetworkResource
   508  	err := json.Unmarshal([]byte(out), &networkResources)
   509  	assert.NilError(c, err)
   510  	assert.Equal(c, len(networkResources), 1)
   511  	container, ok := networkResources[0].Containers[containerID]
   512  	assert.Assert(c, ok)
   513  	assert.Equal(c, container.Name, "testNetInspect1")
   514  
   515  	// rename container and check docker inspect output update
   516  	newName := "HappyNewName"
   517  	cli.DockerCmd(c, "rename", "testNetInspect1", newName)
   518  
   519  	// check whether network inspect works properly
   520  	out = cli.DockerCmd(c, "network", "inspect", "brNetForInspect").Stdout()
   521  	var newNetRes []types.NetworkResource
   522  	err = json.Unmarshal([]byte(out), &newNetRes)
   523  	assert.NilError(c, err)
   524  	assert.Equal(c, len(newNetRes), 1)
   525  	container1, ok := newNetRes[0].Containers[containerID]
   526  	assert.Assert(c, ok)
   527  	assert.Equal(c, container1.Name, newName)
   528  }
   529  
   530  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *testing.T) {
   531  	cli.DockerCmd(c, "network", "create", "test")
   532  	assertNwIsAvailable(c, "test")
   533  	nr := getNwResource(c, "test")
   534  
   535  	assert.Equal(c, nr.Name, "test")
   536  	assert.Equal(c, len(nr.Containers), 0)
   537  
   538  	// run a container
   539  	out := cli.DockerCmd(c, "run", "-d", "--name", "test", "busybox", "top").Stdout()
   540  	cli.WaitRun(c, "test")
   541  	containerID := strings.TrimSpace(out)
   542  
   543  	// connect the container to the test network
   544  	cli.DockerCmd(c, "network", "connect", "test", containerID)
   545  
   546  	// inspect the network to make sure container is connected
   547  	nr = getNetworkResource(c, nr.ID)
   548  	assert.Equal(c, len(nr.Containers), 1)
   549  
   550  	// check if container IP matches network inspect
   551  	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
   552  	assert.NilError(c, err)
   553  	containerIP := findContainerIP(c, "test", "test")
   554  	assert.Equal(c, ip.String(), containerIP)
   555  
   556  	// disconnect container from the network
   557  	cli.DockerCmd(c, "network", "disconnect", "test", containerID)
   558  	nr = getNwResource(c, "test")
   559  	assert.Equal(c, nr.Name, "test")
   560  	assert.Equal(c, len(nr.Containers), 0)
   561  
   562  	// run another container
   563  	out = cli.DockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top").Stdout()
   564  	cli.WaitRun(c, "test2")
   565  	containerID = strings.TrimSpace(out)
   566  
   567  	nr = getNwResource(c, "test")
   568  	assert.Equal(c, nr.Name, "test")
   569  	assert.Equal(c, len(nr.Containers), 1)
   570  
   571  	// force disconnect the container to the test network
   572  	cli.DockerCmd(c, "network", "disconnect", "-f", "test", containerID)
   573  
   574  	nr = getNwResource(c, "test")
   575  	assert.Equal(c, nr.Name, "test")
   576  	assert.Equal(c, len(nr.Containers), 0)
   577  
   578  	cli.DockerCmd(c, "network", "rm", "test")
   579  	assertNwNotAvailable(c, "test")
   580  }
   581  
   582  func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *testing.T) {
   583  	testRequires(c, testEnv.IsLocalDaemon)
   584  	// test0 bridge network
   585  	cli.DockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1")
   586  	assertNwIsAvailable(c, "test1")
   587  
   588  	// test2 bridge network does not overlap
   589  	cli.DockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2")
   590  	assertNwIsAvailable(c, "test2")
   591  
   592  	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
   593  	cli.DockerCmd(c, "network", "create", "test3")
   594  	assertNwIsAvailable(c, "test3")
   595  	cli.DockerCmd(c, "network", "create", "test4")
   596  	assertNwIsAvailable(c, "test4")
   597  	cli.DockerCmd(c, "network", "create", "test5")
   598  	assertNwIsAvailable(c, "test5")
   599  
   600  	// test network with multiple subnets
   601  	// bridge network doesn't support multiple subnets. hence, use a dummy driver that supports
   602  
   603  	cli.DockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.170.0.0/16", "--subnet=192.171.0.0/16", "test6")
   604  	assertNwIsAvailable(c, "test6")
   605  
   606  	// test network with multiple subnets with valid ipam combinations
   607  	// also check same subnet across networks when the driver supports it.
   608  	cli.DockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
   609  		"--subnet=192.172.0.0/16", "--subnet=192.173.0.0/16",
   610  		"--gateway=192.172.0.100", "--gateway=192.173.0.100",
   611  		"--ip-range=192.172.1.0/24",
   612  		"--aux-address", "a=192.172.1.5", "--aux-address", "b=192.172.1.6",
   613  		"--aux-address", "c=192.173.1.5", "--aux-address", "d=192.173.1.6",
   614  		"test7")
   615  	assertNwIsAvailable(c, "test7")
   616  
   617  	// cleanup
   618  	for i := 1; i < 8; i++ {
   619  		cli.DockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i))
   620  	}
   621  }
   622  
   623  func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *testing.T) {
   624  	testRequires(c, testEnv.IsLocalDaemon)
   625  	// Create a bridge network using custom ipam driver
   626  	cli.DockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0")
   627  	assertNwIsAvailable(c, "br0")
   628  
   629  	// Verify expected network ipam fields are there
   630  	nr := getNetworkResource(c, "br0")
   631  	assert.Equal(c, nr.Driver, "bridge")
   632  	assert.Equal(c, nr.IPAM.Driver, dummyIPAMDriver)
   633  
   634  	// remove network and exercise remote ipam driver
   635  	cli.DockerCmd(c, "network", "rm", "br0")
   636  	assertNwNotAvailable(c, "br0")
   637  }
   638  
   639  func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *testing.T) {
   640  	testRequires(c, testEnv.IsLocalDaemon)
   641  	// Create a bridge network using custom ipam driver and options
   642  	cli.DockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0")
   643  	assertNwIsAvailable(c, "br0")
   644  
   645  	// Verify expected network ipam options
   646  	nr := getNetworkResource(c, "br0")
   647  	opts := nr.IPAM.Options
   648  	assert.Equal(c, opts["opt1"], "drv1")
   649  	assert.Equal(c, opts["opt2"], "drv2")
   650  }
   651  
   652  func (s *DockerNetworkSuite) TestDockerNetworkNullIPAMDriver(c *testing.T) {
   653  	testRequires(c, testEnv.IsLocalDaemon)
   654  	// Create a network with null ipam driver
   655  	_, _, err := dockerCmdWithError("network", "create", "-d", dummyNetworkDriver, "--ipam-driver", "null", "test000")
   656  	assert.NilError(c, err)
   657  	assertNwIsAvailable(c, "test000")
   658  
   659  	// Verify the inspect data contains the default subnet provided by the null
   660  	// ipam driver and no gateway, as the null ipam driver does not provide one
   661  	nr := getNetworkResource(c, "test000")
   662  	assert.Equal(c, nr.IPAM.Driver, "null")
   663  	assert.Equal(c, len(nr.IPAM.Config), 1)
   664  	assert.Equal(c, nr.IPAM.Config[0].Subnet, "0.0.0.0/0")
   665  	assert.Equal(c, nr.IPAM.Config[0].Gateway, "")
   666  }
   667  
   668  func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *testing.T) {
   669  	nr := getNetworkResource(c, "none")
   670  	assert.Equal(c, nr.Driver, "null")
   671  	assert.Equal(c, nr.Scope, "local")
   672  	assert.Equal(c, nr.Internal, false)
   673  	assert.Equal(c, nr.EnableIPv6, false)
   674  	assert.Equal(c, nr.IPAM.Driver, "default")
   675  	assert.Equal(c, len(nr.IPAM.Config), 0)
   676  
   677  	nr = getNetworkResource(c, "host")
   678  	assert.Equal(c, nr.Driver, "host")
   679  	assert.Equal(c, nr.Scope, "local")
   680  	assert.Equal(c, nr.Internal, false)
   681  	assert.Equal(c, nr.EnableIPv6, false)
   682  	assert.Equal(c, nr.IPAM.Driver, "default")
   683  	assert.Equal(c, len(nr.IPAM.Config), 0)
   684  
   685  	nr = getNetworkResource(c, "bridge")
   686  	assert.Equal(c, nr.Driver, "bridge")
   687  	assert.Equal(c, nr.Scope, "local")
   688  	assert.Equal(c, nr.Internal, false)
   689  	assert.Equal(c, nr.EnableIPv6, false)
   690  	assert.Equal(c, nr.IPAM.Driver, "default")
   691  	assert.Equal(c, len(nr.IPAM.Config), 1)
   692  }
   693  
   694  func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *testing.T) {
   695  	// if unspecified, network subnet will be selected from inside preferred pool
   696  	cli.DockerCmd(c, "network", "create", "test01")
   697  	assertNwIsAvailable(c, "test01")
   698  
   699  	nr := getNetworkResource(c, "test01")
   700  	assert.Equal(c, nr.Driver, "bridge")
   701  	assert.Equal(c, nr.Scope, "local")
   702  	assert.Equal(c, nr.Internal, false)
   703  	assert.Equal(c, nr.EnableIPv6, false)
   704  	assert.Equal(c, nr.IPAM.Driver, "default")
   705  	assert.Equal(c, len(nr.IPAM.Config), 1)
   706  
   707  	cli.DockerCmd(c, "network", "rm", "test01")
   708  	assertNwNotAvailable(c, "test01")
   709  }
   710  
   711  func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *testing.T) {
   712  	cli.DockerCmd(c, "network", "create", "--driver=bridge", "--ipv6", "--subnet=fd80:24e2:f998:72d6::/64", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0")
   713  	assertNwIsAvailable(c, "br0")
   714  
   715  	nr := getNetworkResource(c, "br0")
   716  	assert.Equal(c, nr.Driver, "bridge")
   717  	assert.Equal(c, nr.Scope, "local")
   718  	assert.Equal(c, nr.Internal, false)
   719  	assert.Equal(c, nr.EnableIPv6, true)
   720  	assert.Equal(c, nr.IPAM.Driver, "default")
   721  	assert.Equal(c, len(nr.IPAM.Config), 2)
   722  	assert.Equal(c, nr.IPAM.Config[0].Subnet, "172.28.0.0/16")
   723  	assert.Equal(c, nr.IPAM.Config[0].IPRange, "172.28.5.0/24")
   724  	assert.Equal(c, nr.IPAM.Config[0].Gateway, "172.28.5.254")
   725  	assert.Equal(c, nr.Internal, false)
   726  	cli.DockerCmd(c, "network", "rm", "br0")
   727  	assertNwNotAvailable(c, "br0")
   728  }
   729  
   730  func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *testing.T) {
   731  	// network with ip-range out of subnet range
   732  	_, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test")
   733  	assert.ErrorContains(c, err, "")
   734  
   735  	// network with multiple gateways for a single subnet
   736  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test")
   737  	assert.ErrorContains(c, err, "")
   738  
   739  	// Multiple overlapping subnets in the same network must fail
   740  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test")
   741  	assert.ErrorContains(c, err, "")
   742  
   743  	// overlapping subnets across networks must fail
   744  	// create a valid test0 network
   745  	cli.DockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0")
   746  	assertNwIsAvailable(c, "test0")
   747  	// create an overlapping test1 network
   748  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
   749  	assert.ErrorContains(c, err, "")
   750  	cli.DockerCmd(c, "network", "rm", "test0")
   751  	assertNwNotAvailable(c, "test0")
   752  }
   753  
   754  func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *testing.T) {
   755  	testRequires(c, testEnv.IsLocalDaemon)
   756  	cli.DockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt")
   757  	assertNwIsAvailable(c, "testopt")
   758  	gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData]
   759  	assert.Assert(c, gopts != nil)
   760  	opts, ok := gopts.(map[string]interface{})
   761  	assert.Equal(c, ok, true)
   762  	assert.Equal(c, opts["opt1"], "drv1")
   763  	assert.Equal(c, opts["opt2"], "drv2")
   764  	cli.DockerCmd(c, "network", "rm", "testopt")
   765  	assertNwNotAvailable(c, "testopt")
   766  }
   767  
   768  func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *testing.T) {
   769  	testRequires(c, DaemonIsLinux, IsAmd64, Network)
   770  
   771  	var (
   772  		npName        = "tiborvass/test-docker-netplugin"
   773  		npTag         = "latest"
   774  		npNameWithTag = npName + ":" + npTag
   775  	)
   776  	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
   777  	assert.NilError(c, err)
   778  
   779  	out, _, err := dockerCmdWithError("plugin", "ls")
   780  	assert.NilError(c, err)
   781  	assert.Assert(c, strings.Contains(out, npName))
   782  	assert.Assert(c, strings.Contains(out, npTag))
   783  	assert.Assert(c, strings.Contains(out, "true"))
   784  	cli.DockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net")
   785  	assertNwIsAvailable(c, "v2net")
   786  	cli.DockerCmd(c, "network", "rm", "v2net")
   787  	assertNwNotAvailable(c, "v2net")
   788  }
   789  
   790  func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *testing.T) {
   791  	ctx := testutil.GetContext(c)
   792  
   793  	// On default bridge network built-in service discovery should not happen
   794  	hostsFile := "/etc/hosts"
   795  	bridgeName := "external-bridge"
   796  	bridgeIP := "192.169.255.254/24"
   797  	createInterface(c, "bridge", bridgeName, bridgeIP)
   798  	defer deleteInterface(c, bridgeName)
   799  
   800  	s.d.StartWithBusybox(ctx, c, "--bridge", bridgeName)
   801  	defer s.d.Restart(c)
   802  
   803  	// run two containers and store first container's etc/hosts content
   804  	out, err := s.d.Cmd("run", "-d", "busybox", "top")
   805  	assert.NilError(c, err)
   806  	cid1 := strings.TrimSpace(out)
   807  	defer s.d.Cmd("stop", cid1)
   808  
   809  	hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   810  	assert.NilError(c, err)
   811  
   812  	out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
   813  	assert.NilError(c, err)
   814  	cid2 := strings.TrimSpace(out)
   815  
   816  	// verify first container's etc/hosts file has not changed after spawning the second named container
   817  	hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   818  	assert.NilError(c, err)
   819  	assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second container creation", hostsFile))
   820  	// stop container 2 and verify first container's etc/hosts has not changed
   821  	_, err = s.d.Cmd("stop", cid2)
   822  	assert.NilError(c, err)
   823  
   824  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   825  	assert.NilError(c, err)
   826  	assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second container creation", hostsFile))
   827  	// but discovery is on when connecting to non default bridge network
   828  	network := "anotherbridge"
   829  	out, err = s.d.Cmd("network", "create", network)
   830  	assert.NilError(c, err, out)
   831  	defer s.d.Cmd("network", "rm", network)
   832  
   833  	out, err = s.d.Cmd("network", "connect", network, cid1)
   834  	assert.NilError(c, err, out)
   835  
   836  	hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   837  	assert.NilError(c, err)
   838  
   839  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   840  	assert.NilError(c, err)
   841  	assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second network connection", hostsFile))
   842  }
   843  
   844  func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *testing.T) {
   845  	hostsFile := "/etc/hosts"
   846  	cstmBridgeNw := "custom-bridge-nw"
   847  	cstmBridgeNw1 := "custom-bridge-nw1"
   848  
   849  	cli.DockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
   850  	assertNwIsAvailable(c, cstmBridgeNw)
   851  
   852  	// run two anonymous containers and store their etc/hosts content
   853  	out := cli.DockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top").Stdout()
   854  	cid1 := strings.TrimSpace(out)
   855  
   856  	hosts1 := readContainerFileWithExec(c, cid1, hostsFile)
   857  
   858  	out = cli.DockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top").Stdout()
   859  	cid2 := strings.TrimSpace(out)
   860  
   861  	// verify first container etc/hosts file has not changed
   862  	hosts1post := readContainerFileWithExec(c, cid1, hostsFile)
   863  	assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on anonymous container creation", hostsFile))
   864  	// Connect the 2nd container to a new network and verify the
   865  	// first container /etc/hosts file still hasn't changed.
   866  	cli.DockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1)
   867  	assertNwIsAvailable(c, cstmBridgeNw1)
   868  
   869  	cli.DockerCmd(c, "network", "connect", cstmBridgeNw1, cid2)
   870  
   871  	hosts2 := readContainerFileWithExec(c, cid2, hostsFile)
   872  	hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
   873  	assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on container connect", hostsFile))
   874  	// start a named container
   875  	cName := "AnyName"
   876  	out = cli.DockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top").Stdout()
   877  	cid3 := strings.TrimSpace(out)
   878  
   879  	// verify that container 1 and 2 can ping the named container
   880  	cli.DockerCmd(c, "exec", cid1, "ping", "-c", "1", cName)
   881  	cli.DockerCmd(c, "exec", cid2, "ping", "-c", "1", cName)
   882  
   883  	// Stop named container and verify first two containers' etc/hosts file hasn't changed
   884  	cli.DockerCmd(c, "stop", cid3)
   885  	hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
   886  	assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on name container creation", hostsFile))
   887  	hosts2post := readContainerFileWithExec(c, cid2, hostsFile)
   888  	assert.Equal(c, string(hosts2), string(hosts2post), fmt.Sprintf("Unexpected %s change on name container creation", hostsFile))
   889  	// verify that container 1 and 2 can't ping the named container now
   890  	_, _, err := dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName)
   891  	assert.ErrorContains(c, err, "")
   892  	_, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName)
   893  	assert.ErrorContains(c, err, "")
   894  }
   895  
   896  func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *testing.T) {
   897  	// Legacy Link feature must work only on default network, and not across networks
   898  	cnt1 := "container1"
   899  	cnt2 := "container2"
   900  	network := "anotherbridge"
   901  
   902  	// Run first container on default network
   903  	cli.DockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
   904  
   905  	// Create another network and run the second container on it
   906  	cli.DockerCmd(c, "network", "create", network)
   907  	assertNwIsAvailable(c, network)
   908  	cli.DockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
   909  
   910  	// Try launching a container on default network, linking to the first container. Must succeed
   911  	cli.DockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
   912  
   913  	// Try launching a container on default network, linking to the second container. Must fail
   914  	_, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   915  	assert.ErrorContains(c, err, "")
   916  
   917  	// Connect second container to default network. Now a container on default network can link to it
   918  	cli.DockerCmd(c, "network", "connect", "bridge", cnt2)
   919  	cli.DockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   920  }
   921  
   922  func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *testing.T) {
   923  	testRequires(c, testEnv.IsLocalDaemon)
   924  	// Verify exposed ports are present in ps output when running a container on
   925  	// a network managed by a driver which does not provide the default gateway
   926  	// for the container
   927  	nwn := "ov"
   928  	ctn := "bb"
   929  	port1 := 80
   930  	port2 := 443
   931  	expose1 := fmt.Sprintf("--expose=%d", port1)
   932  	expose2 := fmt.Sprintf("--expose=%d", port2)
   933  
   934  	cli.DockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
   935  	assertNwIsAvailable(c, nwn)
   936  
   937  	cli.DockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top")
   938  
   939  	// Check docker ps o/p for last created container reports the unpublished ports
   940  	unpPort1 := fmt.Sprintf("%d/tcp", port1)
   941  	unpPort2 := fmt.Sprintf("%d/tcp", port2)
   942  	out := cli.DockerCmd(c, "ps", "-n=1").Stdout()
   943  	// Missing unpublished ports in docker ps output
   944  	assert.Assert(c, strings.Contains(out, unpPort1))
   945  	// Missing unpublished ports in docker ps output
   946  	assert.Assert(c, strings.Contains(out, unpPort2))
   947  }
   948  
   949  func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *testing.T) {
   950  	testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon)
   951  
   952  	ctx := testutil.GetContext(c)
   953  	dnd := "dnd"
   954  	did := "did"
   955  
   956  	mux := http.NewServeMux()
   957  	server := httptest.NewServer(mux)
   958  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
   959  
   960  	s.d.StartWithBusybox(ctx, c)
   961  	_, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1")
   962  	assert.NilError(c, err)
   963  
   964  	_, err = s.d.Cmd("run", "-d", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "top")
   965  	assert.NilError(c, err)
   966  
   967  	// Kill daemon and restart
   968  	assert.Assert(c, s.d.Kill() == nil)
   969  
   970  	server.Close()
   971  
   972  	startTime := time.Now().Unix()
   973  	s.d.Restart(c)
   974  	lapse := time.Now().Unix() - startTime
   975  	if lapse > 60 {
   976  		// In normal scenarios, daemon restart takes ~1 second.
   977  		// Plugin retry mechanism can delay the daemon start. systemd may not like it.
   978  		// Avoid accessing plugins during daemon bootup
   979  		c.Logf("daemon restart took too long : %d seconds", lapse)
   980  	}
   981  
   982  	// Restart the custom dummy plugin
   983  	mux = http.NewServeMux()
   984  	server = httptest.NewServer(mux)
   985  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
   986  
   987  	// trying to reuse the same ip must succeed
   988  	_, err = s.d.Cmd("run", "-d", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "top")
   989  	assert.NilError(c, err)
   990  }
   991  
   992  func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *testing.T) {
   993  	testRequires(c, testEnv.IsLocalDaemon)
   994  	// Verify endpoint MAC address is correctly populated in container's network settings
   995  	nwn := "ov"
   996  	ctn := "bb"
   997  
   998  	cli.DockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
   999  	assertNwIsAvailable(c, nwn)
  1000  
  1001  	cli.DockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top")
  1002  
  1003  	mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress")
  1004  	assert.Equal(c, mac, "a0:b1:c2:d3:e4:f5")
  1005  }
  1006  
  1007  func (s *DockerCLINetworkSuite) TestInspectAPIMultipleNetworks(c *testing.T) {
  1008  	cli.DockerCmd(c, "network", "create", "mybridge1")
  1009  	cli.DockerCmd(c, "network", "create", "mybridge2")
  1010  	out := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout()
  1011  	id := strings.TrimSpace(out)
  1012  	cli.WaitRun(c, id)
  1013  
  1014  	cli.DockerCmd(c, "network", "connect", "mybridge1", id)
  1015  	cli.DockerCmd(c, "network", "connect", "mybridge2", id)
  1016  
  1017  	// Current API version (API v1.21 and up)
  1018  	body := getInspectBody(c, "", id)
  1019  	var inspectCurrent types.ContainerJSON
  1020  	err := json.Unmarshal(body, &inspectCurrent)
  1021  	assert.NilError(c, err)
  1022  	assert.Equal(c, len(inspectCurrent.NetworkSettings.Networks), 3)
  1023  
  1024  	bridge := inspectCurrent.NetworkSettings.Networks["bridge"]
  1025  	assert.Equal(c, bridge.IPAddress, inspectCurrent.NetworkSettings.IPAddress)
  1026  }
  1027  
  1028  func connectContainerToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  1029  	// Run a container on the default network
  1030  	out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
  1031  	assert.NilError(c, err, out)
  1032  
  1033  	// Attach the container to other networks
  1034  	for _, nw := range nws {
  1035  		out, err = d.Cmd("network", "create", nw)
  1036  		assert.NilError(c, err, out)
  1037  		out, err = d.Cmd("network", "connect", nw, cName)
  1038  		assert.NilError(c, err, out)
  1039  	}
  1040  }
  1041  
  1042  func verifyContainerIsConnectedToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  1043  	// Verify container is connected to all the networks
  1044  	for _, nw := range nws {
  1045  		out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
  1046  		assert.NilError(c, err, out)
  1047  		assert.Assert(c, out != "<no value>\n")
  1048  	}
  1049  }
  1050  
  1051  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *testing.T) {
  1052  	testRequires(c, testEnv.IsLocalDaemon)
  1053  	ctx := testutil.GetContext(c)
  1054  	cName := "bb"
  1055  	nwList := []string{"nw1", "nw2", "nw3"}
  1056  
  1057  	s.d.StartWithBusybox(ctx, c)
  1058  
  1059  	connectContainerToNetworks(c, s.d, cName, nwList)
  1060  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1061  
  1062  	// Reload daemon
  1063  	s.d.Restart(c)
  1064  
  1065  	_, err := s.d.Cmd("start", cName)
  1066  	assert.NilError(c, err)
  1067  
  1068  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1069  }
  1070  
  1071  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *testing.T) {
  1072  	testRequires(c, testEnv.IsLocalDaemon)
  1073  	ctx := testutil.GetContext(c)
  1074  	cName := "cc"
  1075  	nwList := []string{"nw1", "nw2", "nw3"}
  1076  
  1077  	s.d.StartWithBusybox(ctx, c)
  1078  
  1079  	connectContainerToNetworks(c, s.d, cName, nwList)
  1080  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1081  
  1082  	// Kill daemon and restart
  1083  	assert.Assert(c, s.d.Kill() == nil)
  1084  	s.d.Restart(c)
  1085  
  1086  	// Restart container
  1087  	_, err := s.d.Cmd("start", cName)
  1088  	assert.NilError(c, err)
  1089  
  1090  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1091  }
  1092  
  1093  func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *testing.T) {
  1094  	out := cli.DockerCmd(c, "network", "create", "one").Stdout()
  1095  	containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
  1096  	assert.Assert(c, err == nil, containerOut)
  1097  }
  1098  
  1099  func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *testing.T) {
  1100  	testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon)
  1101  	ctx := testutil.GetContext(c)
  1102  	s.d.StartWithBusybox(ctx, c)
  1103  
  1104  	// Run a few containers on host network
  1105  	for i := 0; i < 10; i++ {
  1106  		cName := fmt.Sprintf("hostc-%d", i)
  1107  		out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
  1108  		assert.NilError(c, err, out)
  1109  
  1110  		// verify container has finished starting before killing daemon
  1111  		err = s.d.WaitRun(cName)
  1112  		assert.NilError(c, err)
  1113  	}
  1114  
  1115  	// Kill daemon ungracefully and restart
  1116  	assert.Assert(c, s.d.Kill() == nil)
  1117  	s.d.Restart(c)
  1118  
  1119  	// make sure all the containers are up and running
  1120  	for i := 0; i < 10; i++ {
  1121  		err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i))
  1122  		assert.NilError(c, err)
  1123  	}
  1124  }
  1125  
  1126  func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *testing.T) {
  1127  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
  1128  	cli.WaitRun(c, "container1")
  1129  	cli.DockerCmd(c, "network", "disconnect", "bridge", "container1")
  1130  	out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
  1131  	assert.ErrorContains(c, err, "", out)
  1132  	assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  1133  }
  1134  
  1135  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *testing.T) {
  1136  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
  1137  	cli.WaitRun(c, "container1")
  1138  	out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
  1139  	assert.Assert(c, err != nil, "Should err out disconnect from host")
  1140  	assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  1141  }
  1142  
  1143  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *testing.T) {
  1144  	cli.DockerCmd(c, "network", "create", "test1")
  1145  	cli.DockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
  1146  	cli.WaitRun(c, "c1")
  1147  	cli.DockerCmd(c, "network", "connect", "test1", "c1")
  1148  }
  1149  
  1150  func verifyPortMap(c *testing.T, container, port, originalMapping string, mustBeEqual bool) {
  1151  	currentMapping := cli.DockerCmd(c, "port", container, port).Stdout()
  1152  	if mustBeEqual {
  1153  		assert.Equal(c, currentMapping, originalMapping)
  1154  	} else {
  1155  		assert.Assert(c, currentMapping != originalMapping)
  1156  	}
  1157  }
  1158  
  1159  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *testing.T) {
  1160  	// Connect and disconnect a container with explicit and non-explicit
  1161  	// host port mapping to/from networks which do cause and do not cause
  1162  	// the container default gateway to change, and verify docker port cmd
  1163  	// returns congruent information
  1164  	cnt := "c1"
  1165  	cli.DockerCmd(c, "network", "create", "aaa")
  1166  	cli.DockerCmd(c, "network", "create", "ccc")
  1167  
  1168  	cli.DockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
  1169  	cli.WaitRun(c, cnt)
  1170  	curPortMap := cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1171  	curExplPortMap := cli.DockerCmd(c, "port", cnt, "90").Stdout()
  1172  
  1173  	// Connect to a network which causes the container's default gw switch
  1174  	cli.DockerCmd(c, "network", "connect", "aaa", cnt)
  1175  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1176  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1177  
  1178  	// Read current mapping
  1179  	curPortMap = cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1180  
  1181  	// Disconnect from a network which causes the container's default gw switch
  1182  	cli.DockerCmd(c, "network", "disconnect", "aaa", cnt)
  1183  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1184  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1185  
  1186  	// Read current mapping
  1187  	curPortMap = cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1188  
  1189  	// Connect to a network which does not cause the container's default gw switch
  1190  	cli.DockerCmd(c, "network", "connect", "ccc", cnt)
  1191  	verifyPortMap(c, cnt, "70", curPortMap, true)
  1192  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1193  }
  1194  
  1195  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *testing.T) {
  1196  	macAddress := "02:42:ac:11:00:02"
  1197  	cli.DockerCmd(c, "network", "create", "mynetwork")
  1198  	cli.DockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
  1199  	cli.WaitRun(c, "test")
  1200  	mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
  1201  	assert.Equal(c, strings.TrimSpace(mac1), macAddress)
  1202  	cli.DockerCmd(c, "network", "connect", "mynetwork", "test")
  1203  	mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
  1204  	assert.Assert(c, strings.TrimSpace(mac2) != strings.TrimSpace(mac1))
  1205  }
  1206  
  1207  func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *testing.T) {
  1208  	cli.DockerCmd(c, "create", "--name", "test", "busybox")
  1209  	networks := inspectField(c, "test", "NetworkSettings.Networks")
  1210  	assert.Assert(c, strings.Contains(networks, "bridge"), "Should return 'bridge' network")
  1211  }
  1212  
  1213  func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *testing.T) {
  1214  	cli.DockerCmd(c, "network", "create", "test")
  1215  	cli.DockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
  1216  	cli.WaitRun(c, "foo")
  1217  	cli.DockerCmd(c, "network", "connect", "test", "foo")
  1218  	cli.DockerCmd(c, "restart", "foo")
  1219  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1220  	assert.Assert(c, strings.Contains(networks, "bridge"), "Should contain 'bridge' network")
  1221  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1222  }
  1223  
  1224  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *testing.T) {
  1225  	testRequires(c, testEnv.IsLocalDaemon)
  1226  	cli.DockerCmd(c, "network", "create", "test")
  1227  	cli.DockerCmd(c, "create", "--name=foo", "busybox", "top")
  1228  	cli.DockerCmd(c, "network", "connect", "test", "foo")
  1229  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1230  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1231  	// Restart docker daemon to test the config has persisted to disk
  1232  	s.d.Restart(c)
  1233  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1234  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1235  	// start the container and test if we can ping it from another container in the same network
  1236  	cli.DockerCmd(c, "start", "foo")
  1237  	cli.WaitRun(c, "foo")
  1238  	ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
  1239  	ip = strings.TrimSpace(ip)
  1240  	cli.DockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
  1241  
  1242  	cli.DockerCmd(c, "stop", "foo")
  1243  
  1244  	// Test disconnect
  1245  	cli.DockerCmd(c, "network", "disconnect", "test", "foo")
  1246  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1247  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1248  	// Restart docker daemon to test the config has persisted to disk
  1249  	s.d.Restart(c)
  1250  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1251  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1252  }
  1253  
  1254  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *testing.T) {
  1255  	cli.DockerCmd(c, "network", "create", "test")
  1256  	cli.DockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
  1257  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1258  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1259  	// Stop container and remove network
  1260  	cli.DockerCmd(c, "stop", "foo")
  1261  	cli.DockerCmd(c, "network", "rm", "test")
  1262  
  1263  	// Test disconnecting stopped container from nonexisting network
  1264  	cli.DockerCmd(c, "network", "disconnect", "-f", "test", "foo")
  1265  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1266  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1267  }
  1268  
  1269  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *testing.T) {
  1270  	// create two networks
  1271  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
  1272  	assertNwIsAvailable(c, "n0")
  1273  
  1274  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1")
  1275  	assertNwIsAvailable(c, "n1")
  1276  
  1277  	// run a container on first network specifying the ip addresses
  1278  	cli.DockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1279  	cli.WaitRun(c, "c0")
  1280  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1281  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1282  
  1283  	// connect the container to the second network specifying an ip addresses
  1284  	cli.DockerCmd(c, "network", "connect", "--ip", "172.30.5.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
  1285  	verifyIPAddressConfig(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1286  	verifyIPAddresses(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1287  
  1288  	// Stop and restart the container
  1289  	cli.DockerCmd(c, "stop", "c0")
  1290  	cli.DockerCmd(c, "start", "c0")
  1291  
  1292  	// verify requested addresses are applied and configs are still there
  1293  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1294  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1295  	verifyIPAddressConfig(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1296  	verifyIPAddresses(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1297  
  1298  	// Still it should fail to connect to the default network with a specified IP (whatever ip)
  1299  	out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
  1300  	assert.Assert(c, err != nil, "out: %s", out)
  1301  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1302  }
  1303  
  1304  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *testing.T) {
  1305  	// create a container
  1306  	cli.DockerCmd(c, "create", "--name", "c0", "busybox", "top")
  1307  
  1308  	// create a network
  1309  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
  1310  	assertNwIsAvailable(c, "n0")
  1311  
  1312  	// connect the container to the network specifying an ip addresses
  1313  	cli.DockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
  1314  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1315  
  1316  	// start the container, verify config has not changed and ip addresses are assigned
  1317  	cli.DockerCmd(c, "start", "c0")
  1318  	cli.WaitRun(c, "c0")
  1319  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1320  	verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1321  
  1322  	// stop the container and check ip config has not changed
  1323  	cli.DockerCmd(c, "stop", "c0")
  1324  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1325  }
  1326  
  1327  func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *testing.T) {
  1328  	// requested IP is not supported on predefined networks
  1329  	for _, mode := range []string{"none", "host", "bridge", "default"} {
  1330  		checkUnsupportedNetworkAndIP(c, mode)
  1331  	}
  1332  
  1333  	// requested IP is not supported on networks with no user defined subnets
  1334  	cli.DockerCmd(c, "network", "create", "n0")
  1335  	assertNwIsAvailable(c, "n0")
  1336  
  1337  	out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
  1338  	assert.Assert(c, err != nil, "out: %s", out)
  1339  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1340  	out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
  1341  	assert.Assert(c, err != nil, "out: %s", out)
  1342  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1343  	cli.DockerCmd(c, "network", "rm", "n0")
  1344  	assertNwNotAvailable(c, "n0")
  1345  }
  1346  
  1347  func checkUnsupportedNetworkAndIP(c *testing.T, nwMode string) {
  1348  	out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1349  	assert.Assert(c, err != nil, "out: %s", out)
  1350  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1351  }
  1352  
  1353  func verifyIPAddressConfig(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1354  	if ipv4 != "" {
  1355  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
  1356  		assert.Equal(c, strings.TrimSpace(out), ipv4)
  1357  	}
  1358  
  1359  	if ipv6 != "" {
  1360  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
  1361  		assert.Equal(c, strings.TrimSpace(out), ipv6)
  1362  	}
  1363  }
  1364  
  1365  func verifyIPAddresses(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1366  	out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
  1367  	assert.Equal(c, strings.TrimSpace(out), ipv4)
  1368  
  1369  	out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
  1370  	assert.Equal(c, strings.TrimSpace(out), ipv6)
  1371  }
  1372  
  1373  func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *testing.T) {
  1374  	// create one test network
  1375  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0")
  1376  	assertNwIsAvailable(c, "n0")
  1377  
  1378  	// run a container with incorrect link-local address
  1379  	_, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "true")
  1380  	assert.ErrorContains(c, err, "")
  1381  	_, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "true")
  1382  	assert.ErrorContains(c, err, "")
  1383  
  1384  	// run two containers with link-local ip on the test network
  1385  	cli.DockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
  1386  	cli.WaitRun(c, "c0")
  1387  	cli.DockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
  1388  	cli.WaitRun(c, "c1")
  1389  
  1390  	// run a container on the default network and connect it to the test network specifying a link-local address
  1391  	cli.DockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
  1392  	cli.WaitRun(c, "c2")
  1393  	cli.DockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
  1394  
  1395  	// verify the three containers can ping each other via the link-local addresses
  1396  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1397  	assert.NilError(c, err)
  1398  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1399  	assert.NilError(c, err)
  1400  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1401  	assert.NilError(c, err)
  1402  
  1403  	// Stop and restart the three containers
  1404  	cli.DockerCmd(c, "stop", "c0")
  1405  	cli.DockerCmd(c, "stop", "c1")
  1406  	cli.DockerCmd(c, "stop", "c2")
  1407  	cli.DockerCmd(c, "start", "c0")
  1408  	cli.DockerCmd(c, "start", "c1")
  1409  	cli.DockerCmd(c, "start", "c2")
  1410  
  1411  	// verify the ping again
  1412  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1413  	assert.NilError(c, err)
  1414  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1415  	assert.NilError(c, err)
  1416  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1417  	assert.NilError(c, err)
  1418  }
  1419  
  1420  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectLink(c *testing.T) {
  1421  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1422  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "foo1")
  1423  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "foo2")
  1424  
  1425  	cli.DockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
  1426  	cli.WaitRun(c, "first")
  1427  
  1428  	// run a container in a user-defined network with a link for an existing container
  1429  	// and a link for a container that doesn't exist
  1430  	cli.DockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", "--link=third:bar", "busybox", "top")
  1431  	cli.WaitRun(c, "second")
  1432  
  1433  	// ping to first and its alias FirstInFoo1 must succeed
  1434  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1435  	assert.NilError(c, err)
  1436  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1437  	assert.NilError(c, err)
  1438  
  1439  	// connect first container to foo2 network
  1440  	cli.DockerCmd(c, "network", "connect", "foo2", "first")
  1441  	// connect second container to foo2 network with a different alias for first container
  1442  	cli.DockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
  1443  
  1444  	// ping the new alias in network foo2
  1445  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1446  	assert.NilError(c, err)
  1447  
  1448  	// disconnect first container from foo1 network
  1449  	cli.DockerCmd(c, "network", "disconnect", "foo1", "first")
  1450  
  1451  	// link in foo1 network must fail
  1452  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1453  	assert.ErrorContains(c, err, "")
  1454  
  1455  	// link in foo2 network must succeed
  1456  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1457  	assert.NilError(c, err)
  1458  }
  1459  
  1460  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *testing.T) {
  1461  	netWorkName1 := "test1"
  1462  	netWorkName2 := "test2"
  1463  	containerName := "foo"
  1464  
  1465  	cli.DockerCmd(c, "network", "create", netWorkName1)
  1466  	cli.DockerCmd(c, "network", "create", netWorkName2)
  1467  	cli.DockerCmd(c, "create", "--name", containerName, "busybox", "top")
  1468  	cli.DockerCmd(c, "network", "connect", netWorkName1, containerName)
  1469  	cli.DockerCmd(c, "network", "connect", netWorkName2, containerName)
  1470  	cli.DockerCmd(c, "network", "disconnect", "bridge", containerName)
  1471  
  1472  	cli.DockerCmd(c, "start", containerName)
  1473  	cli.WaitRun(c, containerName)
  1474  	networks := inspectField(c, containerName, "NetworkSettings.Networks")
  1475  	assert.Assert(c, strings.Contains(networks, netWorkName1), fmt.Sprintf("Should contain '%s' network", netWorkName1))
  1476  	assert.Assert(c, strings.Contains(networks, netWorkName2), fmt.Sprintf("Should contain '%s' network", netWorkName2))
  1477  	assert.Assert(c, !strings.Contains(networks, "bridge"), "Should not contain 'bridge' network")
  1478  }
  1479  
  1480  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *testing.T) {
  1481  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1482  
  1483  	defaults := []string{"bridge", "host", "none"}
  1484  	out := cli.DockerCmd(c, "run", "-d", "--net=none", "busybox", "top").Stdout()
  1485  	containerID := strings.TrimSpace(out)
  1486  	for _, nw := range defaults {
  1487  		res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+nw, nw, containerID)
  1488  		assert.ErrorContains(c, err, "")
  1489  		assert.Assert(c, strings.Contains(res, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1490  	}
  1491  }
  1492  
  1493  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *testing.T) {
  1494  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1495  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "net1")
  1496  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "net2")
  1497  
  1498  	cid := cli.DockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox:glibc", "top").Stdout()
  1499  	cli.WaitRun(c, "first")
  1500  
  1501  	cli.DockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
  1502  	cli.WaitRun(c, "second")
  1503  
  1504  	// ping first container and its alias
  1505  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1506  	assert.NilError(c, err)
  1507  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1508  	assert.NilError(c, err)
  1509  
  1510  	// ping first container's short-id alias
  1511  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1512  	assert.NilError(c, err)
  1513  
  1514  	// connect first container to net2 network
  1515  	cli.DockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
  1516  	// connect second container to foo2 network with a different alias for first container
  1517  	cli.DockerCmd(c, "network", "connect", "net2", "second")
  1518  
  1519  	// ping the new alias in network foo2
  1520  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1521  	assert.NilError(c, err)
  1522  
  1523  	// disconnect first container from net1 network
  1524  	cli.DockerCmd(c, "network", "disconnect", "net1", "first")
  1525  
  1526  	// ping to net1 scoped alias "foo" must fail
  1527  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1528  	assert.ErrorContains(c, err, "")
  1529  
  1530  	// ping to net2 scoped alias "bar" must still succeed
  1531  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1532  	assert.NilError(c, err)
  1533  	// ping to net2 scoped alias short-id must still succeed
  1534  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1535  	assert.NilError(c, err)
  1536  
  1537  	// verify the alias option is rejected when running on predefined network
  1538  	out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox:glibc", "true")
  1539  	assert.Assert(c, err != nil, "out: %s", out)
  1540  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1541  	// verify the alias option is rejected when connecting to predefined network
  1542  	out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
  1543  	assert.Assert(c, err != nil, "out: %s", out)
  1544  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1545  }
  1546  
  1547  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectivity(c *testing.T) {
  1548  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1549  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
  1550  
  1551  	cli.DockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox:glibc", "top")
  1552  	cli.WaitRun(c, "c1.net1")
  1553  
  1554  	cli.DockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox:glibc", "top")
  1555  	cli.WaitRun(c, "c2.net1")
  1556  
  1557  	// ping first container by its unqualified name
  1558  	_, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
  1559  	assert.NilError(c, err)
  1560  
  1561  	// ping first container by its qualified name
  1562  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
  1563  	assert.NilError(c, err)
  1564  
  1565  	// ping with first qualified name masked by an additional domain. should fail
  1566  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
  1567  	assert.ErrorContains(c, err, "")
  1568  }
  1569  
  1570  func (s *DockerCLINetworkSuite) TestEmbeddedDNSInvalidInput(c *testing.T) {
  1571  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1572  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "nw1")
  1573  
  1574  	// Sending garbage to embedded DNS shouldn't crash the daemon
  1575  	cli.DockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:bookworm-slim", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
  1576  }
  1577  
  1578  func (s *DockerCLINetworkSuite) TestDockerNetworkConnectFailsNoInspectChange(c *testing.T) {
  1579  	cli.DockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
  1580  	cli.WaitRun(c, "bb")
  1581  	defer cli.DockerCmd(c, "stop", "bb")
  1582  
  1583  	ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1584  
  1585  	// A failing redundant network connect should not alter current container's endpoint settings
  1586  	_, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
  1587  	assert.ErrorContains(c, err, "")
  1588  
  1589  	ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1590  	assert.Equal(c, ns1, ns0)
  1591  }
  1592  
  1593  func (s *DockerCLINetworkSuite) TestDockerNetworkInternalMode(c *testing.T) {
  1594  	cli.DockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
  1595  	assertNwIsAvailable(c, "internal")
  1596  	nr := getNetworkResource(c, "internal")
  1597  	assert.Assert(c, nr.Internal)
  1598  
  1599  	cli.DockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox:glibc", "top")
  1600  	cli.WaitRun(c, "first")
  1601  	cli.DockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox:glibc", "top")
  1602  	cli.WaitRun(c, "second")
  1603  	out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "8.8.8.8")
  1604  	assert.ErrorContains(c, err, "")
  1605  	assert.Assert(c, is.Contains(out, "Network is unreachable"))
  1606  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1607  	assert.NilError(c, err)
  1608  }
  1609  
  1610  // Test for #21401
  1611  func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *testing.T) {
  1612  	cli.DockerCmd(c, "network", "create", "test@#$")
  1613  	assertNwIsAvailable(c, "test@#$")
  1614  	cli.DockerCmd(c, "network", "rm", "test@#$")
  1615  	assertNwNotAvailable(c, "test@#$")
  1616  
  1617  	cli.DockerCmd(c, "network", "create", "kiwl$%^")
  1618  	assertNwIsAvailable(c, "kiwl$%^")
  1619  	cli.DockerCmd(c, "network", "rm", "kiwl$%^")
  1620  	assertNwNotAvailable(c, "kiwl$%^")
  1621  }
  1622  
  1623  func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *testing.T) {
  1624  	ctx := testutil.GetContext(t)
  1625  	s.d.StartWithBusybox(ctx, t, "--live-restore")
  1626  	defer s.d.Stop(t)
  1627  	oldCon := "old"
  1628  
  1629  	_, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
  1630  	if err != nil {
  1631  		t.Fatal(err)
  1632  	}
  1633  	oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
  1634  	if err != nil {
  1635  		t.Fatal(err)
  1636  	}
  1637  	// Kill the daemon
  1638  	if err := s.d.Kill(); err != nil {
  1639  		t.Fatal(err)
  1640  	}
  1641  
  1642  	// restart the daemon
  1643  	s.d.Start(t, "--live-restore")
  1644  
  1645  	// start a new container, the new container's ip should not be the same with
  1646  	// old running container.
  1647  	newCon := "new"
  1648  	_, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
  1649  	if err != nil {
  1650  		t.Fatal(err)
  1651  	}
  1652  	newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
  1653  	if err != nil {
  1654  		t.Fatal(err)
  1655  	}
  1656  	if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
  1657  		t.Fatalf("new container ip should not equal to old running container  ip")
  1658  	}
  1659  
  1660  	// start a new container, the new container should ping old running container
  1661  	_, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
  1662  	if err != nil {
  1663  		t.Fatal(err)
  1664  	}
  1665  
  1666  	// start a new container, trying to publish port 80:80 should fail
  1667  	out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1668  	if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
  1669  		t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
  1670  	}
  1671  
  1672  	// kill old running container and try to allocate again
  1673  	_, err = s.d.Cmd("kill", oldCon)
  1674  	if err != nil {
  1675  		t.Fatal(err)
  1676  	}
  1677  	id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1678  	if err != nil {
  1679  		t.Fatal(err)
  1680  	}
  1681  
  1682  	// Cleanup because these containers will not be shut down by daemon
  1683  	out, err = s.d.Cmd("stop", newCon)
  1684  	if err != nil {
  1685  		t.Fatalf("err: %v %v", err, out)
  1686  	}
  1687  	_, err = s.d.Cmd("stop", strings.TrimSpace(id))
  1688  	if err != nil {
  1689  		t.Fatal(err)
  1690  	}
  1691  }
  1692  
  1693  func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *testing.T) {
  1694  	cli.DockerCmd(c, "network", "create", "user")
  1695  	result := cli.DockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
  1696  	assert.Equal(c, result.ExitCode, 0, fmt.Sprintf("unexpected status code %d (%s)", result.ExitCode, result.Combined()))
  1697  
  1698  	output, status, _ := dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
  1699  	assert.Equal(c, status, 0, fmt.Sprintf("unexpected status code %d (%s)", status, output))
  1700  }
  1701  
  1702  func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *testing.T) {
  1703  	_, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
  1704  	assert.NilError(c, err)
  1705  	assertNwIsAvailable(c, "mynet")
  1706  
  1707  	_, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1708  	assert.NilError(c, err)
  1709  	cli.WaitRun(c, "mynet0")
  1710  	verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1711  	verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1712  
  1713  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
  1714  	assert.ErrorContains(c, err, "invalid IPv4 address")
  1715  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
  1716  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1717  
  1718  	// This is a case of IPv4 address to `--ip6`
  1719  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
  1720  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1721  	// This is a special case of an IPv4-mapped IPv6 address
  1722  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
  1723  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1724  }
  1725  
  1726  // Test case for 26220
  1727  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *testing.T) {
  1728  	out := cli.DockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge").Stdout()
  1729  	network := strings.TrimSpace(out)
  1730  
  1731  	name := "test"
  1732  	cli.DockerCmd(c, "create", "--name", name, "busybox", "top")
  1733  
  1734  	_, _, err := dockerCmdWithError("network", "disconnect", network, name)
  1735  	assert.NilError(c, err)
  1736  }
  1737  
  1738  // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795
  1739  // Validates that conntrack is correctly cleaned once a container is destroyed
  1740  func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *testing.T) {
  1741  	testRequires(c, IsAmd64, DaemonIsLinux, Network, testEnv.IsLocalDaemon)
  1742  
  1743  	// Create a new network
  1744  	cli.DockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
  1745  	assertNwIsAvailable(c, "testbind")
  1746  
  1747  	// Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion
  1748  	cmd := "while true; do echo hello | nc -w 1 -l -u -p 8080; done"
  1749  	cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "busybox", "sh", "-c", cmd)
  1750  
  1751  	// Launch a container client, here the objective is to create a flow that is natted in order to expose the bug
  1752  	cmd = "echo world | nc -w 1 -u 192.168.10.1 8080"
  1753  	cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "busybox", "sh", "-c", cmd)
  1754  
  1755  	// Get all the flows using netlink
  1756  	flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1757  	assert.NilError(c, err)
  1758  	var flowMatch int
  1759  	for _, flow := range flows {
  1760  		// count only the flows that we are interested in, skipping others that can be laying around the host
  1761  		if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1762  			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1763  			flow.Forward.DstPort == 8080 {
  1764  			flowMatch++
  1765  		}
  1766  	}
  1767  	// The client should have created only 1 flow
  1768  	assert.Equal(c, flowMatch, 1)
  1769  
  1770  	// Now delete the server, this will trigger the conntrack cleanup
  1771  	cli.DockerCmd(c, "rm", "-fv", "server")
  1772  
  1773  	// Fetch again all the flows and validate that there is no server flow in the conntrack laying around
  1774  	flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1775  	assert.NilError(c, err)
  1776  	flowMatch = 0
  1777  	for _, flow := range flows {
  1778  		if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1779  			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1780  			flow.Forward.DstPort == 8080 {
  1781  			flowMatch++
  1782  		}
  1783  	}
  1784  	// All the flows have to be gone
  1785  	assert.Equal(c, flowMatch, 0)
  1786  }