github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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/Prakhar-Agarwal-byte/moby/api/types"
    18  	"github.com/Prakhar-Agarwal-byte/moby/api/types/versions/v1p20"
    19  	"github.com/Prakhar-Agarwal-byte/moby/integration-cli/cli"
    20  	"github.com/Prakhar-Agarwal-byte/moby/integration-cli/daemon"
    21  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/driverapi"
    22  	remoteapi "github.com/Prakhar-Agarwal-byte/moby/libnetwork/drivers/remote/api"
    23  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipamapi"
    24  	remoteipam "github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipams/remote/api"
    25  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/netlabel"
    26  	"github.com/Prakhar-Agarwal-byte/moby/pkg/plugins"
    27  	"github.com/Prakhar-Agarwal-byte/moby/pkg/stringid"
    28  	"github.com/Prakhar-Agarwal-byte/moby/runconfig"
    29  	"github.com/Prakhar-Agarwal-byte/moby/testutil"
    30  	testdaemon "github.com/Prakhar-Agarwal-byte/moby/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  	body = getInspectBody(c, "v1.21", id)
  1026  	var inspect121 types.ContainerJSON
  1027  	err = json.Unmarshal(body, &inspect121)
  1028  	assert.NilError(c, err)
  1029  	assert.Equal(c, len(inspect121.NetworkSettings.Networks), 3)
  1030  
  1031  	bridge := inspect121.NetworkSettings.Networks["bridge"]
  1032  	assert.Equal(c, bridge.IPAddress, versionedIP)
  1033  	assert.Equal(c, bridge.IPAddress, inspect121.NetworkSettings.IPAddress)
  1034  }
  1035  
  1036  func connectContainerToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  1037  	// Run a container on the default network
  1038  	out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
  1039  	assert.NilError(c, err, out)
  1040  
  1041  	// Attach the container to other networks
  1042  	for _, nw := range nws {
  1043  		out, err = d.Cmd("network", "create", nw)
  1044  		assert.NilError(c, err, out)
  1045  		out, err = d.Cmd("network", "connect", nw, cName)
  1046  		assert.NilError(c, err, out)
  1047  	}
  1048  }
  1049  
  1050  func verifyContainerIsConnectedToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  1051  	// Verify container is connected to all the networks
  1052  	for _, nw := range nws {
  1053  		out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
  1054  		assert.NilError(c, err, out)
  1055  		assert.Assert(c, out != "<no value>\n")
  1056  	}
  1057  }
  1058  
  1059  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *testing.T) {
  1060  	testRequires(c, testEnv.IsLocalDaemon)
  1061  	ctx := testutil.GetContext(c)
  1062  	cName := "bb"
  1063  	nwList := []string{"nw1", "nw2", "nw3"}
  1064  
  1065  	s.d.StartWithBusybox(ctx, c)
  1066  
  1067  	connectContainerToNetworks(c, s.d, cName, nwList)
  1068  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1069  
  1070  	// Reload daemon
  1071  	s.d.Restart(c)
  1072  
  1073  	_, err := s.d.Cmd("start", cName)
  1074  	assert.NilError(c, err)
  1075  
  1076  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1077  }
  1078  
  1079  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *testing.T) {
  1080  	testRequires(c, testEnv.IsLocalDaemon)
  1081  	ctx := testutil.GetContext(c)
  1082  	cName := "cc"
  1083  	nwList := []string{"nw1", "nw2", "nw3"}
  1084  
  1085  	s.d.StartWithBusybox(ctx, c)
  1086  
  1087  	connectContainerToNetworks(c, s.d, cName, nwList)
  1088  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1089  
  1090  	// Kill daemon and restart
  1091  	assert.Assert(c, s.d.Kill() == nil)
  1092  	s.d.Restart(c)
  1093  
  1094  	// Restart container
  1095  	_, err := s.d.Cmd("start", cName)
  1096  	assert.NilError(c, err)
  1097  
  1098  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1099  }
  1100  
  1101  func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *testing.T) {
  1102  	out := cli.DockerCmd(c, "network", "create", "one").Stdout()
  1103  	containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
  1104  	assert.Assert(c, err == nil, containerOut)
  1105  }
  1106  
  1107  func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *testing.T) {
  1108  	testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon)
  1109  	ctx := testutil.GetContext(c)
  1110  	s.d.StartWithBusybox(ctx, c)
  1111  
  1112  	// Run a few containers on host network
  1113  	for i := 0; i < 10; i++ {
  1114  		cName := fmt.Sprintf("hostc-%d", i)
  1115  		out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
  1116  		assert.NilError(c, err, out)
  1117  
  1118  		// verify container has finished starting before killing daemon
  1119  		err = s.d.WaitRun(cName)
  1120  		assert.NilError(c, err)
  1121  	}
  1122  
  1123  	// Kill daemon ungracefully and restart
  1124  	assert.Assert(c, s.d.Kill() == nil)
  1125  	s.d.Restart(c)
  1126  
  1127  	// make sure all the containers are up and running
  1128  	for i := 0; i < 10; i++ {
  1129  		err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i))
  1130  		assert.NilError(c, err)
  1131  	}
  1132  }
  1133  
  1134  func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *testing.T) {
  1135  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
  1136  	cli.WaitRun(c, "container1")
  1137  	cli.DockerCmd(c, "network", "disconnect", "bridge", "container1")
  1138  	out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
  1139  	assert.ErrorContains(c, err, "", out)
  1140  	assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  1141  }
  1142  
  1143  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *testing.T) {
  1144  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
  1145  	cli.WaitRun(c, "container1")
  1146  	out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
  1147  	assert.Assert(c, err != nil, "Should err out disconnect from host")
  1148  	assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  1149  }
  1150  
  1151  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *testing.T) {
  1152  	cli.DockerCmd(c, "network", "create", "test1")
  1153  	cli.DockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
  1154  	cli.WaitRun(c, "c1")
  1155  	cli.DockerCmd(c, "network", "connect", "test1", "c1")
  1156  }
  1157  
  1158  func verifyPortMap(c *testing.T, container, port, originalMapping string, mustBeEqual bool) {
  1159  	currentMapping := cli.DockerCmd(c, "port", container, port).Stdout()
  1160  	if mustBeEqual {
  1161  		assert.Equal(c, currentMapping, originalMapping)
  1162  	} else {
  1163  		assert.Assert(c, currentMapping != originalMapping)
  1164  	}
  1165  }
  1166  
  1167  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *testing.T) {
  1168  	// Connect and disconnect a container with explicit and non-explicit
  1169  	// host port mapping to/from networks which do cause and do not cause
  1170  	// the container default gateway to change, and verify docker port cmd
  1171  	// returns congruent information
  1172  	cnt := "c1"
  1173  	cli.DockerCmd(c, "network", "create", "aaa")
  1174  	cli.DockerCmd(c, "network", "create", "ccc")
  1175  
  1176  	cli.DockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
  1177  	cli.WaitRun(c, cnt)
  1178  	curPortMap := cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1179  	curExplPortMap := cli.DockerCmd(c, "port", cnt, "90").Stdout()
  1180  
  1181  	// Connect to a network which causes the container's default gw switch
  1182  	cli.DockerCmd(c, "network", "connect", "aaa", cnt)
  1183  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1184  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1185  
  1186  	// Read current mapping
  1187  	curPortMap = cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1188  
  1189  	// Disconnect from a network which causes the container's default gw switch
  1190  	cli.DockerCmd(c, "network", "disconnect", "aaa", cnt)
  1191  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1192  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1193  
  1194  	// Read current mapping
  1195  	curPortMap = cli.DockerCmd(c, "port", cnt, "70").Stdout()
  1196  
  1197  	// Connect to a network which does not cause the container's default gw switch
  1198  	cli.DockerCmd(c, "network", "connect", "ccc", cnt)
  1199  	verifyPortMap(c, cnt, "70", curPortMap, true)
  1200  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1201  }
  1202  
  1203  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *testing.T) {
  1204  	macAddress := "02:42:ac:11:00:02"
  1205  	cli.DockerCmd(c, "network", "create", "mynetwork")
  1206  	cli.DockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
  1207  	cli.WaitRun(c, "test")
  1208  	mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
  1209  	assert.Equal(c, strings.TrimSpace(mac1), macAddress)
  1210  	cli.DockerCmd(c, "network", "connect", "mynetwork", "test")
  1211  	mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
  1212  	assert.Assert(c, strings.TrimSpace(mac2) != strings.TrimSpace(mac1))
  1213  }
  1214  
  1215  func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *testing.T) {
  1216  	cli.DockerCmd(c, "create", "--name", "test", "busybox")
  1217  	networks := inspectField(c, "test", "NetworkSettings.Networks")
  1218  	assert.Assert(c, strings.Contains(networks, "bridge"), "Should return 'bridge' network")
  1219  }
  1220  
  1221  func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *testing.T) {
  1222  	cli.DockerCmd(c, "network", "create", "test")
  1223  	cli.DockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
  1224  	cli.WaitRun(c, "foo")
  1225  	cli.DockerCmd(c, "network", "connect", "test", "foo")
  1226  	cli.DockerCmd(c, "restart", "foo")
  1227  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1228  	assert.Assert(c, strings.Contains(networks, "bridge"), "Should contain 'bridge' network")
  1229  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1230  }
  1231  
  1232  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *testing.T) {
  1233  	testRequires(c, testEnv.IsLocalDaemon)
  1234  	cli.DockerCmd(c, "network", "create", "test")
  1235  	cli.DockerCmd(c, "create", "--name=foo", "busybox", "top")
  1236  	cli.DockerCmd(c, "network", "connect", "test", "foo")
  1237  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1238  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1239  	// Restart docker daemon to test the config has persisted to disk
  1240  	s.d.Restart(c)
  1241  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1242  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1243  	// start the container and test if we can ping it from another container in the same network
  1244  	cli.DockerCmd(c, "start", "foo")
  1245  	cli.WaitRun(c, "foo")
  1246  	ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
  1247  	ip = strings.TrimSpace(ip)
  1248  	cli.DockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
  1249  
  1250  	cli.DockerCmd(c, "stop", "foo")
  1251  
  1252  	// Test disconnect
  1253  	cli.DockerCmd(c, "network", "disconnect", "test", "foo")
  1254  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1255  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1256  	// Restart docker daemon to test the config has persisted to disk
  1257  	s.d.Restart(c)
  1258  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1259  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1260  }
  1261  
  1262  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *testing.T) {
  1263  	cli.DockerCmd(c, "network", "create", "test")
  1264  	cli.DockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
  1265  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1266  	assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1267  	// Stop container and remove network
  1268  	cli.DockerCmd(c, "stop", "foo")
  1269  	cli.DockerCmd(c, "network", "rm", "test")
  1270  
  1271  	// Test disconnecting stopped container from nonexisting network
  1272  	cli.DockerCmd(c, "network", "disconnect", "-f", "test", "foo")
  1273  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1274  	assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1275  }
  1276  
  1277  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *testing.T) {
  1278  	// create two networks
  1279  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
  1280  	assertNwIsAvailable(c, "n0")
  1281  
  1282  	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")
  1283  	assertNwIsAvailable(c, "n1")
  1284  
  1285  	// run a container on first network specifying the ip addresses
  1286  	cli.DockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1287  	cli.WaitRun(c, "c0")
  1288  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1289  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1290  
  1291  	// connect the container to the second network specifying an ip addresses
  1292  	cli.DockerCmd(c, "network", "connect", "--ip", "172.30.5.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
  1293  	verifyIPAddressConfig(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1294  	verifyIPAddresses(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1295  
  1296  	// Stop and restart the container
  1297  	cli.DockerCmd(c, "stop", "c0")
  1298  	cli.DockerCmd(c, "start", "c0")
  1299  
  1300  	// verify requested addresses are applied and configs are still there
  1301  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1302  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1303  	verifyIPAddressConfig(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1304  	verifyIPAddresses(c, "c0", "n1", "172.30.5.44", "2001:db8:abcd::5544")
  1305  
  1306  	// Still it should fail to connect to the default network with a specified IP (whatever ip)
  1307  	out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
  1308  	assert.Assert(c, err != nil, "out: %s", out)
  1309  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1310  }
  1311  
  1312  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *testing.T) {
  1313  	// create a container
  1314  	cli.DockerCmd(c, "create", "--name", "c0", "busybox", "top")
  1315  
  1316  	// create a network
  1317  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
  1318  	assertNwIsAvailable(c, "n0")
  1319  
  1320  	// connect the container to the network specifying an ip addresses
  1321  	cli.DockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
  1322  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1323  
  1324  	// start the container, verify config has not changed and ip addresses are assigned
  1325  	cli.DockerCmd(c, "start", "c0")
  1326  	cli.WaitRun(c, "c0")
  1327  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1328  	verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1329  
  1330  	// stop the container and check ip config has not changed
  1331  	cli.DockerCmd(c, "stop", "c0")
  1332  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1333  }
  1334  
  1335  func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *testing.T) {
  1336  	// requested IP is not supported on predefined networks
  1337  	for _, mode := range []string{"none", "host", "bridge", "default"} {
  1338  		checkUnsupportedNetworkAndIP(c, mode)
  1339  	}
  1340  
  1341  	// requested IP is not supported on networks with no user defined subnets
  1342  	cli.DockerCmd(c, "network", "create", "n0")
  1343  	assertNwIsAvailable(c, "n0")
  1344  
  1345  	out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
  1346  	assert.Assert(c, err != nil, "out: %s", out)
  1347  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1348  	out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
  1349  	assert.Assert(c, err != nil, "out: %s", out)
  1350  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1351  	cli.DockerCmd(c, "network", "rm", "n0")
  1352  	assertNwNotAvailable(c, "n0")
  1353  }
  1354  
  1355  func checkUnsupportedNetworkAndIP(c *testing.T, nwMode string) {
  1356  	out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1357  	assert.Assert(c, err != nil, "out: %s", out)
  1358  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1359  }
  1360  
  1361  func verifyIPAddressConfig(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1362  	if ipv4 != "" {
  1363  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
  1364  		assert.Equal(c, strings.TrimSpace(out), ipv4)
  1365  	}
  1366  
  1367  	if ipv6 != "" {
  1368  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
  1369  		assert.Equal(c, strings.TrimSpace(out), ipv6)
  1370  	}
  1371  }
  1372  
  1373  func verifyIPAddresses(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1374  	out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
  1375  	assert.Equal(c, strings.TrimSpace(out), ipv4)
  1376  
  1377  	out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
  1378  	assert.Equal(c, strings.TrimSpace(out), ipv6)
  1379  }
  1380  
  1381  func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *testing.T) {
  1382  	// create one test network
  1383  	cli.DockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0")
  1384  	assertNwIsAvailable(c, "n0")
  1385  
  1386  	// run a container with incorrect link-local address
  1387  	_, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "true")
  1388  	assert.ErrorContains(c, err, "")
  1389  	_, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "true")
  1390  	assert.ErrorContains(c, err, "")
  1391  
  1392  	// run two containers with link-local ip on the test network
  1393  	cli.DockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
  1394  	cli.WaitRun(c, "c0")
  1395  	cli.DockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
  1396  	cli.WaitRun(c, "c1")
  1397  
  1398  	// run a container on the default network and connect it to the test network specifying a link-local address
  1399  	cli.DockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
  1400  	cli.WaitRun(c, "c2")
  1401  	cli.DockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
  1402  
  1403  	// verify the three containers can ping each other via the link-local addresses
  1404  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1405  	assert.NilError(c, err)
  1406  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1407  	assert.NilError(c, err)
  1408  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1409  	assert.NilError(c, err)
  1410  
  1411  	// Stop and restart the three containers
  1412  	cli.DockerCmd(c, "stop", "c0")
  1413  	cli.DockerCmd(c, "stop", "c1")
  1414  	cli.DockerCmd(c, "stop", "c2")
  1415  	cli.DockerCmd(c, "start", "c0")
  1416  	cli.DockerCmd(c, "start", "c1")
  1417  	cli.DockerCmd(c, "start", "c2")
  1418  
  1419  	// verify the ping again
  1420  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1421  	assert.NilError(c, err)
  1422  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1423  	assert.NilError(c, err)
  1424  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1425  	assert.NilError(c, err)
  1426  }
  1427  
  1428  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectLink(c *testing.T) {
  1429  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1430  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "foo1")
  1431  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "foo2")
  1432  
  1433  	cli.DockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
  1434  	cli.WaitRun(c, "first")
  1435  
  1436  	// run a container in a user-defined network with a link for an existing container
  1437  	// and a link for a container that doesn't exist
  1438  	cli.DockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1", "--link=third:bar", "busybox", "top")
  1439  	cli.WaitRun(c, "second")
  1440  
  1441  	// ping to first and its alias FirstInFoo1 must succeed
  1442  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1443  	assert.NilError(c, err)
  1444  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1445  	assert.NilError(c, err)
  1446  
  1447  	// connect first container to foo2 network
  1448  	cli.DockerCmd(c, "network", "connect", "foo2", "first")
  1449  	// connect second container to foo2 network with a different alias for first container
  1450  	cli.DockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
  1451  
  1452  	// ping the new alias in network foo2
  1453  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1454  	assert.NilError(c, err)
  1455  
  1456  	// disconnect first container from foo1 network
  1457  	cli.DockerCmd(c, "network", "disconnect", "foo1", "first")
  1458  
  1459  	// link in foo1 network must fail
  1460  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1461  	assert.ErrorContains(c, err, "")
  1462  
  1463  	// link in foo2 network must succeed
  1464  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1465  	assert.NilError(c, err)
  1466  }
  1467  
  1468  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *testing.T) {
  1469  	netWorkName1 := "test1"
  1470  	netWorkName2 := "test2"
  1471  	containerName := "foo"
  1472  
  1473  	cli.DockerCmd(c, "network", "create", netWorkName1)
  1474  	cli.DockerCmd(c, "network", "create", netWorkName2)
  1475  	cli.DockerCmd(c, "create", "--name", containerName, "busybox", "top")
  1476  	cli.DockerCmd(c, "network", "connect", netWorkName1, containerName)
  1477  	cli.DockerCmd(c, "network", "connect", netWorkName2, containerName)
  1478  	cli.DockerCmd(c, "network", "disconnect", "bridge", containerName)
  1479  
  1480  	cli.DockerCmd(c, "start", containerName)
  1481  	cli.WaitRun(c, containerName)
  1482  	networks := inspectField(c, containerName, "NetworkSettings.Networks")
  1483  	assert.Assert(c, strings.Contains(networks, netWorkName1), fmt.Sprintf("Should contain '%s' network", netWorkName1))
  1484  	assert.Assert(c, strings.Contains(networks, netWorkName2), fmt.Sprintf("Should contain '%s' network", netWorkName2))
  1485  	assert.Assert(c, !strings.Contains(networks, "bridge"), "Should not contain 'bridge' network")
  1486  }
  1487  
  1488  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *testing.T) {
  1489  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1490  
  1491  	defaults := []string{"bridge", "host", "none"}
  1492  	out := cli.DockerCmd(c, "run", "-d", "--net=none", "busybox", "top").Stdout()
  1493  	containerID := strings.TrimSpace(out)
  1494  	for _, nw := range defaults {
  1495  		res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+nw, nw, containerID)
  1496  		assert.ErrorContains(c, err, "")
  1497  		assert.Assert(c, strings.Contains(res, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1498  	}
  1499  }
  1500  
  1501  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *testing.T) {
  1502  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1503  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "net1")
  1504  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "net2")
  1505  
  1506  	cid := cli.DockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox:glibc", "top").Stdout()
  1507  	cli.WaitRun(c, "first")
  1508  
  1509  	cli.DockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
  1510  	cli.WaitRun(c, "second")
  1511  
  1512  	// ping first container and its alias
  1513  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1514  	assert.NilError(c, err)
  1515  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1516  	assert.NilError(c, err)
  1517  
  1518  	// ping first container's short-id alias
  1519  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1520  	assert.NilError(c, err)
  1521  
  1522  	// connect first container to net2 network
  1523  	cli.DockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
  1524  	// connect second container to foo2 network with a different alias for first container
  1525  	cli.DockerCmd(c, "network", "connect", "net2", "second")
  1526  
  1527  	// ping the new alias in network foo2
  1528  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1529  	assert.NilError(c, err)
  1530  
  1531  	// disconnect first container from net1 network
  1532  	cli.DockerCmd(c, "network", "disconnect", "net1", "first")
  1533  
  1534  	// ping to net1 scoped alias "foo" must fail
  1535  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1536  	assert.ErrorContains(c, err, "")
  1537  
  1538  	// ping to net2 scoped alias "bar" must still succeed
  1539  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1540  	assert.NilError(c, err)
  1541  	// ping to net2 scoped alias short-id must still succeed
  1542  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1543  	assert.NilError(c, err)
  1544  
  1545  	// verify the alias option is rejected when running on predefined network
  1546  	out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox:glibc", "true")
  1547  	assert.Assert(c, err != nil, "out: %s", out)
  1548  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1549  	// verify the alias option is rejected when connecting to predefined network
  1550  	out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
  1551  	assert.Assert(c, err != nil, "out: %s", out)
  1552  	assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1553  }
  1554  
  1555  func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectivity(c *testing.T) {
  1556  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1557  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
  1558  
  1559  	cli.DockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox:glibc", "top")
  1560  	cli.WaitRun(c, "c1.net1")
  1561  
  1562  	cli.DockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox:glibc", "top")
  1563  	cli.WaitRun(c, "c2.net1")
  1564  
  1565  	// ping first container by its unqualified name
  1566  	_, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
  1567  	assert.NilError(c, err)
  1568  
  1569  	// ping first container by its qualified name
  1570  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
  1571  	assert.NilError(c, err)
  1572  
  1573  	// ping with first qualified name masked by an additional domain. should fail
  1574  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
  1575  	assert.ErrorContains(c, err, "")
  1576  }
  1577  
  1578  func (s *DockerCLINetworkSuite) TestEmbeddedDNSInvalidInput(c *testing.T) {
  1579  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1580  	cli.DockerCmd(c, "network", "create", "-d", "bridge", "nw1")
  1581  
  1582  	// Sending garbage to embedded DNS shouldn't crash the daemon
  1583  	cli.DockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:bullseye-slim", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
  1584  }
  1585  
  1586  func (s *DockerCLINetworkSuite) TestDockerNetworkConnectFailsNoInspectChange(c *testing.T) {
  1587  	cli.DockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
  1588  	cli.WaitRun(c, "bb")
  1589  	defer cli.DockerCmd(c, "stop", "bb")
  1590  
  1591  	ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1592  
  1593  	// A failing redundant network connect should not alter current container's endpoint settings
  1594  	_, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
  1595  	assert.ErrorContains(c, err, "")
  1596  
  1597  	ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1598  	assert.Equal(c, ns1, ns0)
  1599  }
  1600  
  1601  func (s *DockerCLINetworkSuite) TestDockerNetworkInternalMode(c *testing.T) {
  1602  	cli.DockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
  1603  	assertNwIsAvailable(c, "internal")
  1604  	nr := getNetworkResource(c, "internal")
  1605  	assert.Assert(c, nr.Internal)
  1606  
  1607  	cli.DockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox:glibc", "top")
  1608  	cli.WaitRun(c, "first")
  1609  	cli.DockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox:glibc", "top")
  1610  	cli.WaitRun(c, "second")
  1611  	out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "8.8.8.8")
  1612  	assert.ErrorContains(c, err, "")
  1613  	assert.Assert(c, is.Contains(out, "Network is unreachable"))
  1614  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1615  	assert.NilError(c, err)
  1616  }
  1617  
  1618  // Test for #21401
  1619  func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *testing.T) {
  1620  	cli.DockerCmd(c, "network", "create", "test@#$")
  1621  	assertNwIsAvailable(c, "test@#$")
  1622  	cli.DockerCmd(c, "network", "rm", "test@#$")
  1623  	assertNwNotAvailable(c, "test@#$")
  1624  
  1625  	cli.DockerCmd(c, "network", "create", "kiwl$%^")
  1626  	assertNwIsAvailable(c, "kiwl$%^")
  1627  	cli.DockerCmd(c, "network", "rm", "kiwl$%^")
  1628  	assertNwNotAvailable(c, "kiwl$%^")
  1629  }
  1630  
  1631  func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *testing.T) {
  1632  	ctx := testutil.GetContext(t)
  1633  	s.d.StartWithBusybox(ctx, t, "--live-restore")
  1634  	defer s.d.Stop(t)
  1635  	oldCon := "old"
  1636  
  1637  	_, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
  1638  	if err != nil {
  1639  		t.Fatal(err)
  1640  	}
  1641  	oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
  1642  	if err != nil {
  1643  		t.Fatal(err)
  1644  	}
  1645  	// Kill the daemon
  1646  	if err := s.d.Kill(); err != nil {
  1647  		t.Fatal(err)
  1648  	}
  1649  
  1650  	// restart the daemon
  1651  	s.d.Start(t, "--live-restore")
  1652  
  1653  	// start a new container, the new container's ip should not be the same with
  1654  	// old running container.
  1655  	newCon := "new"
  1656  	_, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
  1657  	if err != nil {
  1658  		t.Fatal(err)
  1659  	}
  1660  	newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
  1661  	if err != nil {
  1662  		t.Fatal(err)
  1663  	}
  1664  	if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
  1665  		t.Fatalf("new container ip should not equal to old running container  ip")
  1666  	}
  1667  
  1668  	// start a new container, the new container should ping old running container
  1669  	_, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
  1670  	if err != nil {
  1671  		t.Fatal(err)
  1672  	}
  1673  
  1674  	// start a new container, trying to publish port 80:80 should fail
  1675  	out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1676  	if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
  1677  		t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
  1678  	}
  1679  
  1680  	// kill old running container and try to allocate again
  1681  	_, err = s.d.Cmd("kill", oldCon)
  1682  	if err != nil {
  1683  		t.Fatal(err)
  1684  	}
  1685  	id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1686  	if err != nil {
  1687  		t.Fatal(err)
  1688  	}
  1689  
  1690  	// Cleanup because these containers will not be shut down by daemon
  1691  	out, err = s.d.Cmd("stop", newCon)
  1692  	if err != nil {
  1693  		t.Fatalf("err: %v %v", err, out)
  1694  	}
  1695  	_, err = s.d.Cmd("stop", strings.TrimSpace(id))
  1696  	if err != nil {
  1697  		t.Fatal(err)
  1698  	}
  1699  }
  1700  
  1701  func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *testing.T) {
  1702  	cli.DockerCmd(c, "network", "create", "user")
  1703  	result := cli.DockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
  1704  	assert.Equal(c, result.ExitCode, 0, fmt.Sprintf("unexpected status code %d (%s)", result.ExitCode, result.Combined()))
  1705  
  1706  	output, status, _ := dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
  1707  	assert.Equal(c, status, 0, fmt.Sprintf("unexpected status code %d (%s)", status, output))
  1708  }
  1709  
  1710  func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *testing.T) {
  1711  	_, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
  1712  	assert.NilError(c, err)
  1713  	assertNwIsAvailable(c, "mynet")
  1714  
  1715  	_, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1716  	assert.NilError(c, err)
  1717  	cli.WaitRun(c, "mynet0")
  1718  	verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1719  	verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1720  
  1721  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
  1722  	assert.ErrorContains(c, err, "invalid IPv4 address")
  1723  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
  1724  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1725  
  1726  	// This is a case of IPv4 address to `--ip6`
  1727  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
  1728  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1729  	// This is a special case of an IPv4-mapped IPv6 address
  1730  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
  1731  	assert.ErrorContains(c, err, "invalid IPv6 address")
  1732  }
  1733  
  1734  // Test case for 26220
  1735  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *testing.T) {
  1736  	out := cli.DockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge").Stdout()
  1737  	network := strings.TrimSpace(out)
  1738  
  1739  	name := "test"
  1740  	cli.DockerCmd(c, "create", "--name", name, "busybox", "top")
  1741  
  1742  	_, _, err := dockerCmdWithError("network", "disconnect", network, name)
  1743  	assert.NilError(c, err)
  1744  }
  1745  
  1746  // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/Prakhar-Agarwal-byte/moby/issues/8795
  1747  // Validates that conntrack is correctly cleaned once a container is destroyed
  1748  func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *testing.T) {
  1749  	testRequires(c, IsAmd64, DaemonIsLinux, Network, testEnv.IsLocalDaemon)
  1750  
  1751  	// Create a new network
  1752  	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")
  1753  	assertNwIsAvailable(c, "testbind")
  1754  
  1755  	// Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion
  1756  	cmd := "while true; do echo hello | nc -w 1 -l -u -p 8080; done"
  1757  	cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "busybox", "sh", "-c", cmd)
  1758  
  1759  	// Launch a container client, here the objective is to create a flow that is natted in order to expose the bug
  1760  	cmd = "echo world | nc -w 1 -u 192.168.10.1 8080"
  1761  	cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "busybox", "sh", "-c", cmd)
  1762  
  1763  	// Get all the flows using netlink
  1764  	flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1765  	assert.NilError(c, err)
  1766  	var flowMatch int
  1767  	for _, flow := range flows {
  1768  		// count only the flows that we are interested in, skipping others that can be laying around the host
  1769  		if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1770  			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1771  			flow.Forward.DstPort == 8080 {
  1772  			flowMatch++
  1773  		}
  1774  	}
  1775  	// The client should have created only 1 flow
  1776  	assert.Equal(c, flowMatch, 1)
  1777  
  1778  	// Now delete the server, this will trigger the conntrack cleanup
  1779  	cli.DockerCmd(c, "rm", "-fv", "server")
  1780  
  1781  	// Fetch again all the flows and validate that there is no server flow in the conntrack laying around
  1782  	flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1783  	assert.NilError(c, err)
  1784  	flowMatch = 0
  1785  	for _, flow := range flows {
  1786  		if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1787  			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1788  			flow.Forward.DstPort == 8080 {
  1789  			flowMatch++
  1790  		}
  1791  	}
  1792  	// All the flows have to be gone
  1793  	assert.Equal(c, flowMatch, 0)
  1794  }