github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/integration-cli/docker_cli_network_unix_test.go (about)

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