18 "github.com/docker/docker/api/types"
19 "github.com/docker/docker/api/types/versions/v1p20"
20 "github.com/docker/docker/integration-cli/checker"
21 "github.com/docker/docker/integration-cli/cli"
22 "github.com/docker/docker/integration-cli/daemon"
23 "github.com/docker/docker/pkg/stringid"
24 icmd "github.com/docker/docker/pkg/testutil/cmd"
25 "github.com/docker/docker/runconfig"
26 "github.com/docker/libnetwork/driverapi"
27 remoteapi "github.com/docker/libnetwork/drivers/remote/api"
28 "github.com/docker/libnetwork/ipamapi"
29 remoteipam "github.com/docker/libnetwork/ipams/remote/api"
30 "github.com/docker/libnetwork/netlabel"
31 "github.com/go-check/check"
32 "github.com/vishvananda/netlink"
35 const dummyNetworkDriver = "dummy-network-driver"
36 const dummyIPAMDriver = "dummy-ipam-driver"
38 var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
41 check.Suite(&DockerNetworkSuite{
46 type DockerNetworkSuite struct {
47 server *httptest.Server
52 func (s *DockerNetworkSuite) SetUpTest(c *check.C) {
53 s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
54 Experimental: testEnv.ExperimentalDaemon(),
58 func (s *DockerNetworkSuite) TearDownTest(c *check.C) {
65 func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
66 mux := http.NewServeMux()
67 s.server = httptest.NewServer(mux)
68 c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
69 setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver)
72 func setupRemoteNetworkDrivers(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
74 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
75 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
76 fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
79 // Network driver implementation
80 mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", 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, `{"Scope":"local"}`)
85 mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
86 err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
88 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
91 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
92 fmt.Fprintf(w, "null")
95 mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
96 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
97 fmt.Fprintf(w, "null")
100 mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
101 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
102 fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
105 mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
106 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
108 veth := &netlink.Veth{
109 LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
110 if err := netlink.LinkAdd(veth); err != nil {
111 fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
113 fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
117 mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
118 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
119 fmt.Fprintf(w, "null")
122 mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
123 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
124 if link, err := netlink.LinkByName("cnt0"); err == nil {
125 netlink.LinkDel(link)
127 fmt.Fprintf(w, "null")
130 // IPAM Driver implementation
132 poolRequest remoteipam.RequestPoolRequest
133 poolReleaseReq remoteipam.ReleasePoolRequest
134 addressRequest remoteipam.RequestAddressRequest
135 addressReleaseReq remoteipam.ReleaseAddressRequest
138 pool = "172.28.0.0/16"
139 poolID = lAS + "/" + pool
140 gw = "172.28.255.254/16"
143 mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
144 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
145 fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
148 mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
149 err := json.NewDecoder(r.Body).Decode(&poolRequest)
151 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
154 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
155 if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
156 fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
157 } else if poolRequest.Pool != "" && poolRequest.Pool != pool {
158 fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
160 fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
164 mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
165 err := json.NewDecoder(r.Body).Decode(&addressRequest)
167 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
170 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
171 // make sure libnetwork is now querying on the expected pool id
172 if addressRequest.PoolID != poolID {
173 fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
174 } else if addressRequest.Address != "" {
175 fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
177 fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
181 mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
182 err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
184 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
187 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
188 // make sure libnetwork is now asking to release the expected address from the expected poolid
189 if addressRequest.PoolID != poolID {
190 fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
191 } else if addressReleaseReq.Address != gw {
192 fmt.Fprintf(w, `{"Error":"unknown address"}`)
194 fmt.Fprintf(w, "null")
198 mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
199 err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
201 http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
204 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
205 // make sure libnetwork is now asking to release the expected poolid
206 if addressRequest.PoolID != poolID {
207 fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
209 fmt.Fprintf(w, "null")
213 err := os.MkdirAll("/etc/docker/plugins", 0755)
214 c.Assert(err, checker.IsNil)
216 fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
217 err = ioutil.WriteFile(fileName, []byte(url), 0644)
218 c.Assert(err, checker.IsNil)
220 ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
221 err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
222 c.Assert(err, checker.IsNil)
225 func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
232 err := os.RemoveAll("/etc/docker/plugins")
233 c.Assert(err, checker.IsNil)
236 func assertNwIsAvailable(c *check.C, name string) {
237 if !isNwPresent(c, name) {
238 c.Fatalf("Network %s not found in network ls o/p", name)
242 func assertNwNotAvailable(c *check.C, name string) {
243 if isNwPresent(c, name) {
244 c.Fatalf("Found network %s in network ls o/p", name)
248 func isNwPresent(c *check.C, name string) bool {
249 out, _ := dockerCmd(c, "network", "ls")
250 lines := strings.Split(out, "\n")
251 for i := 1; i < len(lines)-1; i++ {
252 netFields := strings.Fields(lines[i])
253 if netFields[1] == name {
260 // assertNwList checks network list retrieved with ls command
261 // equals to expected network list
262 // note: out should be `network ls [option]` result
263 func assertNwList(c *check.C, out string, expectNws []string) {
264 lines := strings.Split(out, "\n")
266 for _, line := range lines[1 : len(lines)-1] {
267 netFields := strings.Fields(line)
268 // wrap all network name in nwList
269 nwList = append(nwList, netFields[1])
272 // network ls should contains all expected networks
273 c.Assert(nwList, checker.DeepEquals, expectNws)
276 func getNwResource(c *check.C, name string) *types.NetworkResource {
277 out, _ := dockerCmd(c, "network", "inspect", name)
278 nr := []types.NetworkResource{}
279 err := json.Unmarshal([]byte(out), &nr)
280 c.Assert(err, check.IsNil)
284 func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) {
285 defaults := []string{"bridge", "host", "none"}
286 for _, nn := range defaults {
287 assertNwIsAvailable(c, nn)
291 func (s *DockerSuite) TestNetworkLsFormat(c *check.C) {
292 testRequires(c, DaemonIsLinux)
293 out, _ := dockerCmd(c, "network", "ls", "--format", "{{.Name}}")
294 lines := strings.Split(strings.TrimSpace(string(out)), "\n")
296 expected := []string{"bridge", "host", "none"}
298 names = append(names, lines...)
299 c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
302 func (s *DockerSuite) TestNetworkLsFormatDefaultFormat(c *check.C) {
303 testRequires(c, DaemonIsLinux)
306 "networksFormat": "{{ .Name }} default"
308 d, err := ioutil.TempDir("", "integration-cli-")
309 c.Assert(err, checker.IsNil)
310 defer os.RemoveAll(d)
312 err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
313 c.Assert(err, checker.IsNil)
315 out, _ := dockerCmd(c, "--config", d, "network", "ls")
316 lines := strings.Split(strings.TrimSpace(string(out)), "\n")
318 expected := []string{"bridge default", "host default", "none default"}
320 names = append(names, lines...)
321 c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
324 func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *check.C) {
325 predefined := []string{"bridge", "host", "none", "default"}
326 for _, net := range predefined {
327 // predefined networks can't be created again
328 out, _, err := dockerCmdWithError("network", "create", net)
329 c.Assert(err, checker.NotNil, check.Commentf("%v", out))
333 func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *check.C) {
334 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")
335 assertNwIsAvailable(c, "testbind")
337 out := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000")
338 id := strings.TrimSpace(out)
339 c.Assert(waitRun(id), checker.IsNil)
340 out, _ = dockerCmd(c, "ps")
341 c.Assert(out, checker.Contains, "192.168.10.1:5000->5000/tcp")
344 func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) {
345 predefined := []string{"bridge", "host", "none", "default"}
346 for _, net := range predefined {
347 // predefined networks can't be removed
348 out, _, err := dockerCmdWithError("network", "rm", net)
349 c.Assert(err, checker.NotNil, check.Commentf("%v", out))
353 func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
354 testNet := "testnet1"
357 out, _ := dockerCmd(c, "network", "create", "dev")
359 dockerCmd(c, "network", "rm", "dev")
360 dockerCmd(c, "network", "rm", testNet)
362 networkID := strings.TrimSpace(out)
364 // filter with partial ID
365 // only show 'dev' network
366 out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5])
367 assertNwList(c, out, []string{"dev"})
369 out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge")
370 assertNwList(c, out, []string{"bridge"})
372 // only show built-in network (bridge, none, host)
373 out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
374 assertNwList(c, out, []string{"bridge", "host", "none"})
376 // only show custom networks (dev)
377 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom")
378 assertNwList(c, out, []string{"dev"})
380 // show all networks with filter
381 // it should be equivalent of ls without option
382 out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
383 assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
385 out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
386 assertNwIsAvailable(c, testNet)
388 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel)
389 assertNwList(c, out, []string{testNet})
391 out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue)
392 assertNwList(c, out, []string{testNet})
394 out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent")
395 outArr := strings.Split(strings.TrimSpace(out), "\n")
396 c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
398 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=null")
399 assertNwList(c, out, []string{"none"})
401 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=host")
402 assertNwList(c, out, []string{"host"})
404 out, _ = dockerCmd(c, "network", "ls", "-f", "driver=bridge")
405 assertNwList(c, out, []string{"bridge", "dev", testNet})
408 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
409 dockerCmd(c, "network", "create", "test")
410 assertNwIsAvailable(c, "test")
412 dockerCmd(c, "network", "rm", "test")
413 assertNwNotAvailable(c, "test")
416 func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *check.C) {
417 testNet := "testnetcreatelabel"
421 dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
422 assertNwIsAvailable(c, testNet)
424 out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet)
425 c.Assert(err, check.IsNil)
426 c.Assert(strings.TrimSpace(out), check.Equals, testValue)
428 dockerCmd(c, "network", "rm", testNet)
429 assertNwNotAvailable(c, testNet)
432 func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) {
433 out, _, err := dockerCmdWithError("network", "rm", "test")
434 c.Assert(err, checker.NotNil, check.Commentf("%v", out))
437 func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) {
438 dockerCmd(c, "network", "create", "testDelMulti0")
439 assertNwIsAvailable(c, "testDelMulti0")
440 dockerCmd(c, "network", "create", "testDelMulti1")
441 assertNwIsAvailable(c, "testDelMulti1")
442 dockerCmd(c, "network", "create", "testDelMulti2")
443 assertNwIsAvailable(c, "testDelMulti2")
444 out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top")
445 containerID := strings.TrimSpace(out)
448 // delete three networks at the same time, since testDelMulti2
449 // contains active container, its deletion should fail.
450 out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2")
451 // err should not be nil due to deleting testDelMulti2 failed.
452 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
453 // testDelMulti2 should fail due to network has active endpoints
454 c.Assert(out, checker.Contains, "has active endpoints")
455 assertNwNotAvailable(c, "testDelMulti0")
456 assertNwNotAvailable(c, "testDelMulti1")
457 // testDelMulti2 can't be deleted, so it should exist
458 assertNwIsAvailable(c, "testDelMulti2")
461 func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) {
462 out, _ := dockerCmd(c, "network", "inspect", "host")
463 networkResources := []types.NetworkResource{}
464 err := json.Unmarshal([]byte(out), &networkResources)
465 c.Assert(err, check.IsNil)
466 c.Assert(networkResources, checker.HasLen, 1)
468 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host")
469 c.Assert(strings.TrimSpace(out), check.Equals, "host")
472 func (s *DockerSuite) TestDockerNetworkInspectWithID(c *check.C) {
473 out, _ := dockerCmd(c, "network", "create", "test2")
474 networkID := strings.TrimSpace(out)
475 assertNwIsAvailable(c, "test2")
476 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2")
477 c.Assert(strings.TrimSpace(out), check.Equals, networkID)
479 out, _ = dockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2")
480 c.Assert(strings.TrimSpace(out), check.Equals, networkID)
483 func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) {
484 result := dockerCmdWithResult("network", "inspect", "host", "none")
485 c.Assert(result, icmd.Matches, icmd.Success)
487 networkResources := []types.NetworkResource{}
488 err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
489 c.Assert(err, check.IsNil)
490 c.Assert(networkResources, checker.HasLen, 2)
493 func (s *DockerSuite) TestDockerInspectMultipleNetworksIncludingNonexistent(c *check.C) {
494 // non-existent network was not at the beginning of the inspect list
495 // This should print an error, return an exitCode 1 and print the host network
496 result := dockerCmdWithResult("network", "inspect", "host", "nonexistent")
497 c.Assert(result, icmd.Matches, icmd.Expected{
499 Err: "Error: No such network: nonexistent",
503 networkResources := []types.NetworkResource{}
504 err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
505 c.Assert(err, check.IsNil)
506 c.Assert(networkResources, checker.HasLen, 1)
508 // Only one non-existent network to inspect
509 // Should print an error and return an exitCode, nothing else
510 result = dockerCmdWithResult("network", "inspect", "nonexistent")
511 c.Assert(result, icmd.Matches, icmd.Expected{
513 Err: "Error: No such network: nonexistent",
517 // non-existent network was at the beginning of the inspect list
518 // Should not fail fast, and still print host network but print an error
519 result = dockerCmdWithResult("network", "inspect", "nonexistent", "host")
520 c.Assert(result, icmd.Matches, icmd.Expected{
522 Err: "Error: No such network: nonexistent",
526 networkResources = []types.NetworkResource{}
527 err = json.Unmarshal([]byte(result.Stdout()), &networkResources)
528 c.Assert(err, check.IsNil)
529 c.Assert(networkResources, checker.HasLen, 1)
532 func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) {
533 dockerCmd(c, "network", "create", "brNetForInspect")
534 assertNwIsAvailable(c, "brNetForInspect")
536 dockerCmd(c, "network", "rm", "brNetForInspect")
537 assertNwNotAvailable(c, "brNetForInspect")
540 out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top")
541 c.Assert(waitRun("testNetInspect1"), check.IsNil)
542 containerID := strings.TrimSpace(out)
544 // we don't stop container by name, because we'll rename it later
545 dockerCmd(c, "stop", containerID)
548 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
549 networkResources := []types.NetworkResource{}
550 err := json.Unmarshal([]byte(out), &networkResources)
551 c.Assert(err, check.IsNil)
552 c.Assert(networkResources, checker.HasLen, 1)
553 container, ok := networkResources[0].Containers[containerID]
554 c.Assert(ok, checker.True)
555 c.Assert(container.Name, checker.Equals, "testNetInspect1")
557 // rename container and check docker inspect output update
558 newName := "HappyNewName"
559 dockerCmd(c, "rename", "testNetInspect1", newName)
561 // check whether network inspect works properly
562 out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
563 newNetRes := []types.NetworkResource{}
564 err = json.Unmarshal([]byte(out), &newNetRes)
565 c.Assert(err, check.IsNil)
566 c.Assert(newNetRes, checker.HasLen, 1)
567 container1, ok := newNetRes[0].Containers[containerID]
568 c.Assert(ok, checker.True)
569 c.Assert(container1.Name, checker.Equals, newName)
573 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
574 dockerCmd(c, "network", "create", "test")
575 assertNwIsAvailable(c, "test")
576 nr := getNwResource(c, "test")
578 c.Assert(nr.Name, checker.Equals, "test")
579 c.Assert(len(nr.Containers), checker.Equals, 0)
582 out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
583 c.Assert(waitRun("test"), check.IsNil)
584 containerID := strings.TrimSpace(out)
586 // connect the container to the test network
587 dockerCmd(c, "network", "connect", "test", containerID)
589 // inspect the network to make sure container is connected
590 nr = getNetworkResource(c, nr.ID)
591 c.Assert(len(nr.Containers), checker.Equals, 1)
592 c.Assert(nr.Containers[containerID], check.NotNil)
594 // check if container IP matches network inspect
595 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
596 c.Assert(err, check.IsNil)
597 containerIP := findContainerIP(c, "test", "test")
598 c.Assert(ip.String(), checker.Equals, containerIP)
600 // disconnect container from the network
601 dockerCmd(c, "network", "disconnect", "test", containerID)
602 nr = getNwResource(c, "test")
603 c.Assert(nr.Name, checker.Equals, "test")
604 c.Assert(len(nr.Containers), checker.Equals, 0)
606 // run another container
607 out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top")
608 c.Assert(waitRun("test2"), check.IsNil)
609 containerID = strings.TrimSpace(out)
611 nr = getNwResource(c, "test")
612 c.Assert(nr.Name, checker.Equals, "test")
613 c.Assert(len(nr.Containers), checker.Equals, 1)
615 // force disconnect the container to the test network
616 dockerCmd(c, "network", "disconnect", "-f", "test", containerID)
618 nr = getNwResource(c, "test")
619 c.Assert(nr.Name, checker.Equals, "test")
620 c.Assert(len(nr.Containers), checker.Equals, 0)
622 dockerCmd(c, "network", "rm", "test")
623 assertNwNotAvailable(c, "test")
626 func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *check.C) {
627 // test0 bridge network
628 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1")
629 assertNwIsAvailable(c, "test1")
631 // test2 bridge network does not overlap
632 dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2")
633 assertNwIsAvailable(c, "test2")
635 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets
636 dockerCmd(c, "network", "create", "test3")
637 assertNwIsAvailable(c, "test3")
638 dockerCmd(c, "network", "create", "test4")
639 assertNwIsAvailable(c, "test4")
640 dockerCmd(c, "network", "create", "test5")
641 assertNwIsAvailable(c, "test5")
643 // test network with multiple subnets
644 // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports
646 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6")
647 assertNwIsAvailable(c, "test6")
649 // test network with multiple subnets with valid ipam combinations
650 // also check same subnet across networks when the driver supports it.
651 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
652 "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16",
653 "--gateway=192.168.0.100", "--gateway=192.170.0.100",
654 "--ip-range=192.168.1.0/24",
655 "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6",
656 "--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6",
658 assertNwIsAvailable(c, "test7")
661 for i := 1; i < 8; i++ {
662 dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i))
666 func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *check.C) {
667 // Create a bridge network using custom ipam driver
668 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0")
669 assertNwIsAvailable(c, "br0")
671 // Verify expected network ipam fields are there
672 nr := getNetworkResource(c, "br0")
673 c.Assert(nr.Driver, checker.Equals, "bridge")
674 c.Assert(nr.IPAM.Driver, checker.Equals, dummyIPAMDriver)
676 // remove network and exercise remote ipam driver
677 dockerCmd(c, "network", "rm", "br0")
678 assertNwNotAvailable(c, "br0")
681 func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *check.C) {
682 // Create a bridge network using custom ipam driver and options
683 dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0")
684 assertNwIsAvailable(c, "br0")
686 // Verify expected network ipam options
687 nr := getNetworkResource(c, "br0")
688 opts := nr.IPAM.Options
689 c.Assert(opts["opt1"], checker.Equals, "drv1")
690 c.Assert(opts["opt2"], checker.Equals, "drv2")
693 func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) {
694 nr := getNetworkResource(c, "none")
695 c.Assert(nr.Driver, checker.Equals, "null")
696 c.Assert(nr.Scope, checker.Equals, "local")
697 c.Assert(nr.Internal, checker.Equals, false)
698 c.Assert(nr.EnableIPv6, checker.Equals, false)
699 c.Assert(nr.IPAM.Driver, checker.Equals, "default")
700 c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
702 nr = getNetworkResource(c, "host")
703 c.Assert(nr.Driver, checker.Equals, "host")
704 c.Assert(nr.Scope, checker.Equals, "local")
705 c.Assert(nr.Internal, checker.Equals, false)
706 c.Assert(nr.EnableIPv6, checker.Equals, false)
707 c.Assert(nr.IPAM.Driver, checker.Equals, "default")
708 c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
710 nr = getNetworkResource(c, "bridge")
711 c.Assert(nr.Driver, checker.Equals, "bridge")
712 c.Assert(nr.Scope, checker.Equals, "local")
713 c.Assert(nr.Internal, checker.Equals, false)
714 c.Assert(nr.EnableIPv6, checker.Equals, false)
715 c.Assert(nr.IPAM.Driver, checker.Equals, "default")
716 c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
717 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
718 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
721 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) {
722 // if unspecified, network subnet will be selected from inside preferred pool
723 dockerCmd(c, "network", "create", "test01")
724 assertNwIsAvailable(c, "test01")
726 nr := getNetworkResource(c, "test01")
727 c.Assert(nr.Driver, checker.Equals, "bridge")
728 c.Assert(nr.Scope, checker.Equals, "local")
729 c.Assert(nr.Internal, checker.Equals, false)
730 c.Assert(nr.EnableIPv6, checker.Equals, false)
731 c.Assert(nr.IPAM.Driver, checker.Equals, "default")
732 c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
733 c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
734 c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
736 dockerCmd(c, "network", "rm", "test01")
737 assertNwNotAvailable(c, "test01")
740 func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) {
741 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")
742 assertNwIsAvailable(c, "br0")
744 nr := getNetworkResource(c, "br0")
745 c.Assert(nr.Driver, checker.Equals, "bridge")
746 c.Assert(nr.Scope, checker.Equals, "local")
747 c.Assert(nr.Internal, checker.Equals, false)
748 c.Assert(nr.EnableIPv6, checker.Equals, true)
749 c.Assert(nr.IPAM.Driver, checker.Equals, "default")
750 c.Assert(len(nr.IPAM.Config), checker.Equals, 2)
751 c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
752 c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
753 c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
754 c.Assert(nr.Internal, checker.False)
755 dockerCmd(c, "network", "rm", "br0")
756 assertNwNotAvailable(c, "test01")
759 func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *check.C) {
760 // network with ip-range out of subnet range
761 _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test")
762 c.Assert(err, check.NotNil)
764 // network with multiple gateways for a single subnet
765 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test")
766 c.Assert(err, check.NotNil)
768 // Multiple overlapping subnets in the same network must fail
769 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test")
770 c.Assert(err, check.NotNil)
772 // overlapping subnets across networks must fail
773 // create a valid test0 network
774 dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0")
775 assertNwIsAvailable(c, "test0")
776 // create an overlapping test1 network
777 _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
778 c.Assert(err, check.NotNil)
779 dockerCmd(c, "network", "rm", "test0")
780 assertNwNotAvailable(c, "test0")
783 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
784 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt")
785 assertNwIsAvailable(c, "testopt")
786 gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData]
787 c.Assert(gopts, checker.NotNil)
788 opts, ok := gopts.(map[string]interface{})
789 c.Assert(ok, checker.Equals, true)
790 c.Assert(opts["opt1"], checker.Equals, "drv1")
791 c.Assert(opts["opt2"], checker.Equals, "drv2")
792 dockerCmd(c, "network", "rm", "testopt")
793 assertNwNotAvailable(c, "testopt")
797 func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) {
798 c.Skip("Plugins aren't supported")
800 testRequires(c, DaemonIsLinux, IsAmd64, Network)
803 npName = "tiborvass/test-docker-netplugin"
805 npNameWithTag = npName + ":" + npTag
807 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
808 c.Assert(err, checker.IsNil)
810 out, _, err := dockerCmdWithError("plugin", "ls")
811 c.Assert(err, checker.IsNil)
812 c.Assert(out, checker.Contains, npName)
813 c.Assert(out, checker.Contains, npTag)
814 c.Assert(out, checker.Contains, "true")
816 dockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net")
817 assertNwIsAvailable(c, "v2net")
818 dockerCmd(c, "network", "rm", "v2net")
819 assertNwNotAvailable(c, "v2net")
823 func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) {
824 testRequires(c, ExecSupport)
825 // On default bridge network built-in service discovery should not happen
826 hostsFile := "/etc/hosts"
827 bridgeName := "external-bridge"
828 bridgeIP := "192.169.255.254/24"
829 createInterface(c, "bridge", bridgeName, bridgeIP)
830 defer deleteInterface(c, bridgeName)
832 s.d.StartWithBusybox(c, "--bridge", bridgeName)
835 // run two containers and store first container's etc/hosts content
836 out, err := s.d.Cmd("run", "-d", "busybox", "top")
837 c.Assert(err, check.IsNil)
838 cid1 := strings.TrimSpace(out)
839 defer s.d.Cmd("stop", cid1)
841 hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
842 c.Assert(err, checker.IsNil)
844 out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
845 c.Assert(err, check.IsNil)
846 cid2 := strings.TrimSpace(out)
848 // verify first container's etc/hosts file has not changed after spawning the second named container
849 hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
850 c.Assert(err, checker.IsNil)
851 c.Assert(string(hosts), checker.Equals, string(hostsPost),
852 check.Commentf("Unexpected %s change on second container creation", hostsFile))
854 // stop container 2 and verify first container's etc/hosts has not changed
855 _, err = s.d.Cmd("stop", cid2)
856 c.Assert(err, check.IsNil)
858 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
859 c.Assert(err, checker.IsNil)
860 c.Assert(string(hosts), checker.Equals, string(hostsPost),
861 check.Commentf("Unexpected %s change on second container creation", hostsFile))
863 // but discovery is on when connecting to non default bridge network
864 network := "anotherbridge"
865 out, err = s.d.Cmd("network", "create", network)
866 c.Assert(err, check.IsNil, check.Commentf(out))
867 defer s.d.Cmd("network", "rm", network)
869 out, err = s.d.Cmd("network", "connect", network, cid1)
870 c.Assert(err, check.IsNil, check.Commentf(out))
872 hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
873 c.Assert(err, checker.IsNil)
875 hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
876 c.Assert(err, checker.IsNil)
877 c.Assert(string(hosts), checker.Equals, string(hostsPost),
878 check.Commentf("Unexpected %s change on second network connection", hostsFile))
881 func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) {
882 testRequires(c, ExecSupport, NotArm)
883 hostsFile := "/etc/hosts"
884 cstmBridgeNw := "custom-bridge-nw"
885 cstmBridgeNw1 := "custom-bridge-nw1"
887 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
888 assertNwIsAvailable(c, cstmBridgeNw)
890 // run two anonymous containers and store their etc/hosts content
891 out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
892 cid1 := strings.TrimSpace(out)
894 hosts1 := readContainerFileWithExec(c, cid1, hostsFile)
896 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
897 cid2 := strings.TrimSpace(out)
899 hosts2 := readContainerFileWithExec(c, cid2, hostsFile)
901 // verify first container etc/hosts file has not changed
902 hosts1post := readContainerFileWithExec(c, cid1, hostsFile)
903 c.Assert(string(hosts1), checker.Equals, string(hosts1post),
904 check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
906 // Connect the 2nd container to a new network and verify the
907 // first container /etc/hosts file still hasn't changed.
908 dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1)
909 assertNwIsAvailable(c, cstmBridgeNw1)
911 dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2)
913 hosts2 = readContainerFileWithExec(c, cid2, hostsFile)
914 hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
915 c.Assert(string(hosts1), checker.Equals, string(hosts1post),
916 check.Commentf("Unexpected %s change on container connect", hostsFile))
918 // start a named container
920 out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top")
921 cid3 := strings.TrimSpace(out)
923 // verify that container 1 and 2 can ping the named container
924 dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName)
925 dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName)
927 // Stop named container and verify first two containers' etc/hosts file hasn't changed
928 dockerCmd(c, "stop", cid3)
929 hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
930 c.Assert(string(hosts1), checker.Equals, string(hosts1post),
931 check.Commentf("Unexpected %s change on name container creation", hostsFile))
933 hosts2post := readContainerFileWithExec(c, cid2, hostsFile)
934 c.Assert(string(hosts2), checker.Equals, string(hosts2post),
935 check.Commentf("Unexpected %s change on name container creation", hostsFile))
937 // verify that container 1 and 2 can't ping the named container now
938 _, _, err := dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName)
939 c.Assert(err, check.NotNil)
940 _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName)
941 c.Assert(err, check.NotNil)
944 func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) {
945 // Legacy Link feature must work only on default network, and not across networks
948 network := "anotherbridge"
950 // Run first container on default network
951 dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
953 // Create another network and run the second container on it
954 dockerCmd(c, "network", "create", network)
955 assertNwIsAvailable(c, network)
956 dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
958 // Try launching a container on default network, linking to the first container. Must succeed
959 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
961 // Try launching a container on default network, linking to the second container. Must fail
962 _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
963 c.Assert(err, checker.NotNil)
965 // Connect second container to default network. Now a container on default network can link to it
966 dockerCmd(c, "network", "connect", "bridge", cnt2)
967 dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
970 func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) {
971 // Verify exposed ports are present in ps output when running a container on
972 // a network managed by a driver which does not provide the default gateway
978 expose1 := fmt.Sprintf("--expose=%d", port1)
979 expose2 := fmt.Sprintf("--expose=%d", port2)
981 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
982 assertNwIsAvailable(c, nwn)
984 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top")
986 // Check docker ps o/p for last created container reports the unpublished ports
987 unpPort1 := fmt.Sprintf("%d/tcp", port1)
988 unpPort2 := fmt.Sprintf("%d/tcp", port2)
989 out, _ := dockerCmd(c, "ps", "-n=1")
990 // Missing unpublished ports in docker ps output
991 c.Assert(out, checker.Contains, unpPort1)
992 // Missing unpublished ports in docker ps output
993 c.Assert(out, checker.Contains, unpPort2)
996 func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *check.C) {
997 testRequires(c, DaemonIsLinux, NotUserNamespace)
1001 mux := http.NewServeMux()
1002 server := httptest.NewServer(mux)
1003 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
1005 s.d.StartWithBusybox(c)
1006 _, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1")
1007 c.Assert(err, checker.IsNil)
1009 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "sh")
1010 c.Assert(err, checker.IsNil)
1012 // Kill daemon and restart
1013 c.Assert(s.d.Kill(), checker.IsNil)
1017 startTime := time.Now().Unix()
1019 lapse := time.Now().Unix() - startTime
1021 // In normal scenarios, daemon restart takes ~1 second.
1022 // Plugin retry mechanism can delay the daemon start. systemd may not like it.
1023 // Avoid accessing plugins during daemon bootup
1024 c.Logf("daemon restart took too long : %d seconds", lapse)
1027 // Restart the custom dummy plugin
1028 mux = http.NewServeMux()
1029 server = httptest.NewServer(mux)
1030 setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
1032 // trying to reuse the same ip must succeed
1033 _, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "sh")
1034 c.Assert(err, checker.IsNil)
1037 func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) {
1038 // Verify endpoint MAC address is correctly populated in container's network settings
1042 dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
1043 assertNwIsAvailable(c, nwn)
1045 dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top")
1047 mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress")
1048 c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5")
1051 func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) {
1052 dockerCmd(c, "network", "create", "mybridge1")
1053 dockerCmd(c, "network", "create", "mybridge2")
1054 out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
1055 id := strings.TrimSpace(out)
1056 c.Assert(waitRun(id), check.IsNil)
1058 dockerCmd(c, "network", "connect", "mybridge1", id)
1059 dockerCmd(c, "network", "connect", "mybridge2", id)
1061 body := getInspectBody(c, "v1.20", id)
1062 var inspect120 v1p20.ContainerJSON
1063 err := json.Unmarshal(body, &inspect120)
1064 c.Assert(err, checker.IsNil)
1066 versionedIP := inspect120.NetworkSettings.IPAddress
1068 body = getInspectBody(c, "v1.21", id)
1069 var inspect121 types.ContainerJSON
1070 err = json.Unmarshal(body, &inspect121)
1071 c.Assert(err, checker.IsNil)
1072 c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3)
1074 bridge := inspect121.NetworkSettings.Networks["bridge"]
1075 c.Assert(bridge.IPAddress, checker.Equals, versionedIP)
1076 c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress)
1079 func connectContainerToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) {
1080 // Run a container on the default network
1081 out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
1082 c.Assert(err, checker.IsNil, check.Commentf(out))
1084 // Attach the container to other networks
1085 for _, nw := range nws {
1086 out, err = d.Cmd("network", "create", nw)
1087 c.Assert(err, checker.IsNil, check.Commentf(out))
1088 out, err = d.Cmd("network", "connect", nw, cName)
1089 c.Assert(err, checker.IsNil, check.Commentf(out))
1093 func verifyContainerIsConnectedToNetworks(c *check.C, d *daemon.Daemon, cName string, nws []string) {
1094 // Verify container is connected to all the networks
1095 for _, nw := range nws {
1096 out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
1097 c.Assert(err, checker.IsNil, check.Commentf(out))
1098 c.Assert(out, checker.Not(checker.Equals), "<no value>\n")
1102 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) {
1104 nwList := []string{"nw1", "nw2", "nw3"}
1106 s.d.StartWithBusybox(c)
1108 connectContainerToNetworks(c, s.d, cName, nwList)
1109 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
1114 _, err := s.d.Cmd("start", cName)
1115 c.Assert(err, checker.IsNil)
1117 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
1120 func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) {
1122 nwList := []string{"nw1", "nw2", "nw3"}
1124 s.d.StartWithBusybox(c)
1126 connectContainerToNetworks(c, s.d, cName, nwList)
1127 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
1129 // Kill daemon and restart
1130 c.Assert(s.d.Kill(), checker.IsNil)
1133 // Restart container
1134 _, err := s.d.Cmd("start", cName)
1135 c.Assert(err, checker.IsNil)
1137 verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
1140 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) {
1141 out, _ := dockerCmd(c, "network", "create", "one")
1142 containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
1143 c.Assert(err, checker.IsNil, check.Commentf(containerOut))
1146 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) {
1147 testRequires(c, DaemonIsLinux, NotUserNamespace)
1148 s.d.StartWithBusybox(c)
1150 // Run a few containers on host network
1151 for i := 0; i < 10; i++ {
1152 cName := fmt.Sprintf("hostc-%d", i)
1153 out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
1154 c.Assert(err, checker.IsNil, check.Commentf(out))
1156 // verfiy container has finished starting before killing daemon
1157 err = s.d.WaitRun(cName)
1158 c.Assert(err, checker.IsNil)
1161 // Kill daemon ungracefully and restart
1162 c.Assert(s.d.Kill(), checker.IsNil)
1165 // make sure all the containers are up and running
1166 for i := 0; i < 10; i++ {
1167 err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i))
1168 c.Assert(err, checker.IsNil)
1172 func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) {
1173 dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
1174 c.Assert(waitRun("container1"), check.IsNil)
1175 dockerCmd(c, "network", "disconnect", "bridge", "container1")
1176 out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
1177 c.Assert(err, checker.NotNil, check.Commentf(out))
1178 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
1181 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) {
1182 dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
1183 c.Assert(waitRun("container1"), check.IsNil)
1184 out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
1185 c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host"))
1186 c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
1189 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) {
1190 testRequires(c, NotArm)
1191 dockerCmd(c, "network", "create", "test1")
1192 dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
1193 c.Assert(waitRun("c1"), check.IsNil)
1194 dockerCmd(c, "network", "connect", "test1", "c1")
1197 func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) {
1198 chk := checker.Equals
1200 chk = checker.Not(checker.Equals)
1202 currentMapping, _ := dockerCmd(c, "port", container, port)
1203 c.Assert(currentMapping, chk, originalMapping)
1206 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) {
1207 // Connect and disconnect a container with explicit and non-explicit
1208 // host port mapping to/from networks which do cause and do not cause
1209 // the container default gateway to change, and verify docker port cmd
1210 // returns congruent information
1211 testRequires(c, NotArm)
1213 dockerCmd(c, "network", "create", "aaa")
1214 dockerCmd(c, "network", "create", "ccc")
1216 dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
1217 c.Assert(waitRun(cnt), check.IsNil)
1218 curPortMap, _ := dockerCmd(c, "port", cnt, "70")
1219 curExplPortMap, _ := dockerCmd(c, "port", cnt, "90")
1221 // Connect to a network which causes the container's default gw switch
1222 dockerCmd(c, "network", "connect", "aaa", cnt)
1223 verifyPortMap(c, cnt, "70", curPortMap, false)
1224 verifyPortMap(c, cnt, "90", curExplPortMap, true)
1226 // Read current mapping
1227 curPortMap, _ = dockerCmd(c, "port", cnt, "70")
1229 // Disconnect from a network which causes the container's default gw switch
1230 dockerCmd(c, "network", "disconnect", "aaa", cnt)
1231 verifyPortMap(c, cnt, "70", curPortMap, false)
1232 verifyPortMap(c, cnt, "90", curExplPortMap, true)
1234 // Read current mapping
1235 curPortMap, _ = dockerCmd(c, "port", cnt, "70")
1237 // Connect to a network which does not cause the container's default gw switch
1238 dockerCmd(c, "network", "connect", "ccc", cnt)
1239 verifyPortMap(c, cnt, "70", curPortMap, true)
1240 verifyPortMap(c, cnt, "90", curExplPortMap, true)
1243 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) {
1244 macAddress := "02:42:ac:11:00:02"
1245 dockerCmd(c, "network", "create", "mynetwork")
1246 dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
1247 c.Assert(waitRun("test"), check.IsNil)
1248 mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
1249 c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress)
1250 dockerCmd(c, "network", "connect", "mynetwork", "test")
1251 mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
1252 c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1))
1255 func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) {
1256 dockerCmd(c, "create", "--name", "test", "busybox")
1257 networks := inspectField(c, "test", "NetworkSettings.Networks")
1258 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network"))
1261 func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) {
1262 dockerCmd(c, "network", "create", "test")
1263 dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
1264 c.Assert(waitRun("foo"), checker.IsNil)
1265 dockerCmd(c, "network", "connect", "test", "foo")
1266 dockerCmd(c, "restart", "foo")
1267 networks := inspectField(c, "foo", "NetworkSettings.Networks")
1268 c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network"))
1269 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
1272 func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) {
1273 dockerCmd(c, "network", "create", "test")
1274 dockerCmd(c, "create", "--name=foo", "busybox", "top")
1275 dockerCmd(c, "network", "connect", "test", "foo")
1276 networks := inspectField(c, "foo", "NetworkSettings.Networks")
1277 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
1279 // Restart docker daemon to test the config has persisted to disk
1281 networks = inspectField(c, "foo", "NetworkSettings.Networks")
1282 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
1284 // start the container and test if we can ping it from another container in the same network
1285 dockerCmd(c, "start", "foo")
1286 c.Assert(waitRun("foo"), checker.IsNil)
1287 ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
1288 ip = strings.TrimSpace(ip)
1289 dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
1291 dockerCmd(c, "stop", "foo")
1294 dockerCmd(c, "network", "disconnect", "test", "foo")
1295 networks = inspectField(c, "foo", "NetworkSettings.Networks")
1296 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
1298 // Restart docker daemon to test the config has persisted to disk
1300 networks = inspectField(c, "foo", "NetworkSettings.Networks")
1301 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
1305 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) {
1306 dockerCmd(c, "network", "create", "test")
1307 dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
1308 networks := inspectField(c, "foo", "NetworkSettings.Networks")
1309 c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
1311 // Stop container and remove network
1312 dockerCmd(c, "stop", "foo")
1313 dockerCmd(c, "network", "rm", "test")
1315 // Test disconnecting stopped container from nonexisting network
1316 dockerCmd(c, "network", "disconnect", "-f", "test", "foo")
1317 networks = inspectField(c, "foo", "NetworkSettings.Networks")
1318 c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
1321 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
1322 // create two networks
1323 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
1324 assertNwIsAvailable(c, "n0")
1326 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")
1327 assertNwIsAvailable(c, "n1")
1329 // run a container on first network specifying the ip addresses
1330 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
1331 c.Assert(waitRun("c0"), check.IsNil)
1332 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
1333 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
1335 // connect the container to the second network specifying an ip addresses
1336 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
1337 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
1338 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
1340 // Stop and restart the container
1341 dockerCmd(c, "stop", "c0")
1342 dockerCmd(c, "start", "c0")
1344 // verify requested addresses are applied and configs are still there
1345 verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
1346 verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
1347 verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
1348 verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
1350 // Still it should fail to connect to the default network with a specified IP (whatever ip)
1351 out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
1352 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1353 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
1357 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) {
1358 // create a container
1359 dockerCmd(c, "create", "--name", "c0", "busybox", "top")
1362 dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
1363 assertNwIsAvailable(c, "n0")
1365 // connect the container to the network specifying an ip addresses
1366 dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
1367 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
1369 // start the container, verify config has not changed and ip addresses are assigned
1370 dockerCmd(c, "start", "c0")
1371 c.Assert(waitRun("c0"), check.IsNil)
1372 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
1373 verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
1375 // stop the container and check ip config has not changed
1376 dockerCmd(c, "stop", "c0")
1377 verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
1380 func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) {
1381 // requested IP is not supported on predefined networks
1382 for _, mode := range []string{"none", "host", "bridge", "default"} {
1383 checkUnsupportedNetworkAndIP(c, mode)
1386 // requested IP is not supported on networks with no user defined subnets
1387 dockerCmd(c, "network", "create", "n0")
1388 assertNwIsAvailable(c, "n0")
1390 out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
1391 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1392 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
1394 out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
1395 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1396 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
1398 dockerCmd(c, "network", "rm", "n0")
1399 assertNwNotAvailable(c, "n0")
1402 func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) {
1403 out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
1404 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1405 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
1408 func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) {
1410 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
1411 c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
1415 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
1416 c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
1420 func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) {
1421 out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
1422 c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
1424 out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
1425 c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
1428 func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) {
1429 // create one test network
1430 dockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0")
1431 assertNwIsAvailable(c, "n0")
1433 // run a container with incorrect link-local address
1434 _, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top")
1435 c.Assert(err, check.NotNil)
1436 _, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top")
1437 c.Assert(err, check.NotNil)
1439 // run two containers with link-local ip on the test network
1440 dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
1441 c.Assert(waitRun("c0"), check.IsNil)
1442 dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
1443 c.Assert(waitRun("c1"), check.IsNil)
1445 // run a container on the default network and connect it to the test network specifying a link-local address
1446 dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
1447 c.Assert(waitRun("c2"), check.IsNil)
1448 dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
1450 // verify the three containers can ping each other via the link-local addresses
1451 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
1452 c.Assert(err, check.IsNil)
1453 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
1454 c.Assert(err, check.IsNil)
1455 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
1456 c.Assert(err, check.IsNil)
1458 // Stop and restart the three containers
1459 dockerCmd(c, "stop", "c0")
1460 dockerCmd(c, "stop", "c1")
1461 dockerCmd(c, "stop", "c2")
1462 dockerCmd(c, "start", "c0")
1463 dockerCmd(c, "start", "c1")
1464 dockerCmd(c, "start", "c2")
1466 // verify the ping again
1467 _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
1468 c.Assert(err, check.IsNil)
1469 _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
1470 c.Assert(err, check.IsNil)
1471 _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
1472 c.Assert(err, check.IsNil)
1475 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) {
1476 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
1477 dockerCmd(c, "network", "create", "-d", "bridge", "foo1")
1478 dockerCmd(c, "network", "create", "-d", "bridge", "foo2")
1480 dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
1481 c.Assert(waitRun("first"), check.IsNil)
1483 // run a container in a user-defined network with a link for an existing container
1484 // and a link for a container that doesn't exist
1485 dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1",
1486 "--link=third:bar", "busybox", "top")
1487 c.Assert(waitRun("second"), check.IsNil)
1489 // ping to first and its alias FirstInFoo1 must succeed
1490 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
1491 c.Assert(err, check.IsNil)
1492 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
1493 c.Assert(err, check.IsNil)
1495 // connect first container to foo2 network
1496 dockerCmd(c, "network", "connect", "foo2", "first")
1497 // connect second container to foo2 network with a different alias for first container
1498 dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
1500 // ping the new alias in network foo2
1501 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
1502 c.Assert(err, check.IsNil)
1504 // disconnect first container from foo1 network
1505 dockerCmd(c, "network", "disconnect", "foo1", "first")
1507 // link in foo1 network must fail
1508 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
1509 c.Assert(err, check.NotNil)
1511 // link in foo2 network must succeed
1512 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
1513 c.Assert(err, check.IsNil)
1516 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) {
1517 netWorkName1 := "test1"
1518 netWorkName2 := "test2"
1519 containerName := "foo"
1521 dockerCmd(c, "network", "create", netWorkName1)
1522 dockerCmd(c, "network", "create", netWorkName2)
1523 dockerCmd(c, "create", "--name", containerName, "busybox", "top")
1524 dockerCmd(c, "network", "connect", netWorkName1, containerName)
1525 dockerCmd(c, "network", "connect", netWorkName2, containerName)
1526 dockerCmd(c, "network", "disconnect", "bridge", containerName)
1528 dockerCmd(c, "start", containerName)
1529 c.Assert(waitRun(containerName), checker.IsNil)
1530 networks := inspectField(c, containerName, "NetworkSettings.Networks")
1531 c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1)))
1532 c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2)))
1533 c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network"))
1536 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) {
1537 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
1539 defaults := []string{"bridge", "host", "none"}
1540 out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
1541 containerID := strings.TrimSpace(out)
1542 for _, net := range defaults {
1543 res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID)
1544 c.Assert(err, checker.NotNil)
1545 c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
1549 func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
1550 testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
1551 dockerCmd(c, "network", "create", "-d", "bridge", "net1")
1552 dockerCmd(c, "network", "create", "-d", "bridge", "net2")
1554 cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top")
1555 c.Assert(waitRun("first"), check.IsNil)
1557 dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
1558 c.Assert(waitRun("second"), check.IsNil)
1560 // ping first container and its alias
1561 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
1562 c.Assert(err, check.IsNil)
1563 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
1564 c.Assert(err, check.IsNil)
1566 // ping first container's short-id alias
1567 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
1568 c.Assert(err, check.IsNil)
1570 // connect first container to net2 network
1571 dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
1572 // connect second container to foo2 network with a different alias for first container
1573 dockerCmd(c, "network", "connect", "net2", "second")
1575 // ping the new alias in network foo2
1576 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
1577 c.Assert(err, check.IsNil)
1579 // disconnect first container from net1 network
1580 dockerCmd(c, "network", "disconnect", "net1", "first")
1582 // ping to net1 scoped alias "foo" must fail
1583 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
1584 c.Assert(err, check.NotNil)
1586 // ping to net2 scoped alias "bar" must still succeed
1587 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
1588 c.Assert(err, check.IsNil)
1589 // ping to net2 scoped alias short-id must still succeed
1590 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
1591 c.Assert(err, check.IsNil)
1593 // verify the alias option is rejected when running on predefined network
1594 out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top")
1595 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1596 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
1598 // verify the alias option is rejected when connecting to predefined network
1599 out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
1600 c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
1601 c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
1604 func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
1605 testRequires(c, DaemonIsLinux, NotUserNamespace)
1606 dockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
1608 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top")
1609 c.Assert(waitRun("c1.net1"), check.IsNil)
1611 dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top")
1612 c.Assert(waitRun("c2.net1"), check.IsNil)
1614 // ping first container by its unqualified name
1615 _, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
1616 c.Assert(err, check.IsNil)
1618 // ping first container by its qualified name
1619 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
1620 c.Assert(err, check.IsNil)
1622 // ping with first qualified name masked by an additional domain. should fail
1623 _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
1624 c.Assert(err, check.NotNil)
1627 func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
1628 testRequires(c, DaemonIsLinux, NotUserNamespace)
1629 dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
1631 // Sending garbage to embedded DNS shouldn't crash the daemon
1632 dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
1635 func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
1636 dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
1637 c.Assert(waitRun("bb"), check.IsNil)
1639 ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
1641 // A failing redundant network connect should not alter current container's endpoint settings
1642 _, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
1643 c.Assert(err, check.NotNil)
1645 ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
1646 c.Assert(ns1, check.Equals, ns0)
1649 func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
1650 dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
1651 assertNwIsAvailable(c, "internal")
1652 nr := getNetworkResource(c, "internal")
1653 c.Assert(nr.Internal, checker.True)
1655 dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top")
1656 c.Assert(waitRun("first"), check.IsNil)
1657 dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top")
1658 c.Assert(waitRun("second"), check.IsNil)
1659 out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
1660 c.Assert(err, check.NotNil)
1661 c.Assert(out, checker.Contains, "ping: bad address")
1662 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
1663 c.Assert(err, check.IsNil)
1667 func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) {
1668 dockerCmd(c, "network", "create", "test@#$")
1669 assertNwIsAvailable(c, "test@#$")
1670 dockerCmd(c, "network", "rm", "test@#$")
1671 assertNwNotAvailable(c, "test@#$")
1673 dockerCmd(c, "network", "create", "kiwl$%^")
1674 assertNwIsAvailable(c, "kiwl$%^")
1675 dockerCmd(c, "network", "rm", "kiwl$%^")
1676 assertNwNotAvailable(c, "kiwl$%^")
1679 func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) {
1680 testRequires(t, DaemonIsLinux)
1681 s.d.StartWithBusybox(t, "--live-restore")
1685 _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
1689 oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
1694 if err := s.d.Kill(); err != nil {
1698 // restart the daemon
1699 s.d.Start(t, "--live-restore")
1701 // start a new container, the new container's ip should not be the same with
1702 // old running container.
1704 _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
1708 newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
1712 if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
1713 t.Fatalf("new container ip should not equal to old running container ip")
1716 // start a new container, the new container should ping old running container
1717 _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
1722 // start a new container, trying to publish port 80:80 should fail
1723 out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
1724 if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
1725 t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
1728 // kill old running container and try to allocate again
1729 _, err = s.d.Cmd("kill", oldCon)
1733 id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
1738 // Cleanup because these containers will not be shut down by daemon
1739 out, err = s.d.Cmd("stop", newCon)
1741 t.Fatalf("err: %v %v", err, string(out))
1743 _, err = s.d.Cmd("stop", strings.TrimSpace(id))
1749 func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) {
1750 dockerCmd(c, "network", "create", "user")
1751 output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
1752 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
1754 output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true")
1755 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
1757 output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
1758 c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
1761 func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) {
1762 _, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
1763 c.Assert(err, check.IsNil)
1764 assertNwIsAvailable(c, "mynet")
1766 _, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
1767 c.Assert(err, check.IsNil)
1768 c.Assert(waitRun("mynet0"), check.IsNil)
1769 verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
1770 verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
1772 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
1773 c.Assert(err.Error(), checker.Contains, "invalid IPv4 address")
1774 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
1775 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
1776 // This is a case of IPv4 address to `--ip6`
1777 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
1778 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
1779 // This is a special case of an IPv4-mapped IPv6 address
1780 _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
1781 c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
1784 // Test case for 26220
1785 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) {
1786 out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge")
1788 network := strings.TrimSpace(out)
1791 dockerCmd(c, "create", "--name", name, "busybox", "top")
1793 _, _, err := dockerCmdWithError("network", "disconnect", network, name)
1794 c.Assert(err, check.IsNil)
1797 // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795
1798 // Validates that conntrack is correctly cleaned once a container is destroyed
1799 func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *check.C) {
1800 testRequires(c, IsAmd64, DaemonIsLinux, Network)
1802 // Create a new network
1803 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")
1804 assertNwIsAvailable(c, "testbind")
1806 // Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion
1807 cmd := "while true; do echo hello | nc -w 1 -lu 8080; done"
1808 cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "appropriate/nc", "sh", "-c", cmd)
1810 // Launch a container client, here the objective is to create a flow that is natted in order to expose the bug
1811 cmd = "echo world | nc -q 1 -u 192.168.10.1 8080"
1812 cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "appropriate/nc", "sh", "-c", cmd)
1814 // Get all the flows using netlink
1815 flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, syscall.AF_INET)
1816 c.Assert(err, check.IsNil)
1818 for _, flow := range flows {
1819 // count only the flows that we are interested in, skipping others that can be laying around the host
1820 if flow.Forward.Protocol == syscall.IPPROTO_UDP &&
1821 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
1822 flow.Forward.DstPort == 8080 {
1826 // The client should have created only 1 flow
1827 c.Assert(flowMatch, checker.Equals, 1)
1829 // Now delete the server, this will trigger the conntrack cleanup
1830 cli.DockerCmd(c, "rm", "-fv", "server")
1832 // Fetch again all the flows and validate that there is no server flow in the conntrack laying around
1833 flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, syscall.AF_INET)
1834 c.Assert(err, check.IsNil)
1836 for _, flow := range flows {
1837 if flow.Forward.Protocol == syscall.IPPROTO_UDP &&
1838 flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
1839 flow.Forward.DstPort == 8080 {
1843 // All the flows have to be gone
1844 c.Assert(flowMatch, checker.Equals, 0)