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