moby/integration-cli/docker_experimental_network_test.go
Vincent Demeester c502fb49dc Use *check.C in StartWithBusybox, Start, Stop and Restart…
… to make sure it doesn't fail. It also introduce StartWithError,
StopWithError and RestartWithError in case we care about the
error (and want the error to happen).

This removes the need to check for error and make the intent more
clear : I want a deamon with busybox loaded on it — if an error occur
it should fail the test, but it's not the test code that has the
responsability to check that.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2016-12-12 09:46:47 +01:00

594 lines
32 KiB
Go

// +build !windows
package main
import (
"os/exec"
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
icmd "github.com/docker/docker/pkg/integration/cmd"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/go-check/check"
)
var (
MacvlanKernelSupport = testRequirement{
func() bool {
const macvlanKernelVer = 3 // minimum macvlan kernel support
const macvlanMajorVer = 9 // minimum macvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
// ensure Kernel version is >= v3.9 for macvlan support
if kv.Kernel < macvlanKernelVer || (kv.Kernel == macvlanKernelVer && kv.Major < macvlanMajorVer) {
return false
}
return true
},
"kernel version failed to meet the minimum macvlan kernel requirement of 3.9",
}
IpvlanKernelSupport = testRequirement{
func() bool {
const ipvlanKernelVer = 4 // minimum ipvlan kernel support
const ipvlanMajorVer = 2 // minimum ipvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
// ensure Kernel version is >= v4.2 for ipvlan support
if kv.Kernel < ipvlanKernelVer || (kv.Kernel == ipvlanKernelVer && kv.Major < ipvlanMajorVer) {
return false
}
return true
},
"kernel version failed to meet the minimum ipvlan kernel requirement of 4.0.0",
}
)
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network specifying the desired sub-interface name
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.60", "dm-persist")
assertNwIsAvailable(c, "dm-persist")
// Restart docker daemon to test the config has persisted to disk
s.d.Restart(c)
// verify network is recreated from persistence
assertNwIsAvailable(c, "dm-persist")
// cleanup the master interface that also collects the slave dev
deleteInterface(c, "dm-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'di' notation represent 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network specifying the desired sub-interface name
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.70", "di-persist")
assertNwIsAvailable(c, "di-persist")
// Restart docker daemon to test the config has persisted to disk
s.d.Restart(c)
// verify network is recreated from persistence
assertNwIsAvailable(c, "di-persist")
// cleanup the master interface that also collects the slave dev
deleteInterface(c, "di-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.50)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network specifying the desired sub-interface name
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.50", "dm-subinterface")
assertNwIsAvailable(c, "dm-subinterface")
// cleanup the master interface which also collects the slave dev
deleteInterface(c, "dm-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.50)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network specifying the desired sub-interface name
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.60", "di-subinterface")
assertNwIsAvailable(c, "di-subinterface")
// cleanup the master interface which also collects the slave dev
deleteInterface(c, "di-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
out, err = createVlanInterface(c, master, "dm-dummy0.40", "40")
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network using an existing parent interface
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-subinterface")
assertNwIsAvailable(c, "dm-subinterface")
// attempt to create another network using the same parent iface that should fail
out, _, err = dockerCmdWithError("network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-parent-net-overlap")
// verify that the overlap returns an error
c.Assert(err, check.NotNil)
// cleanup the master interface which also collects the slave dev
deleteInterface(c, "dm-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
out, err := createMasterDummy(c, master)
c.Assert(err, check.IsNil, check.Commentf(out))
out, err = createVlanInterface(c, master, "di-dummy0.30", "30")
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network using an existing parent interface
dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-subinterface")
assertNwIsAvailable(c, "di-subinterface")
// attempt to create another network using the same parent iface that should fail
out, _, err = dockerCmdWithError("network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-parent-net-overlap")
// verify that the overlap returns an error
c.Assert(err, check.NotNil)
// cleanup the master interface which also collects the slave dev
deleteInterface(c, "di-dummy0")
}
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
// create a dual stack multi-subnet Macvlan bridge mode network and validate connectivity between four containers, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.100.0/24", "--subnet=172.28.102.0/24", "--gateway=172.28.102.254",
"--subnet=2001:db8:abc2::/64", "--subnet=2001:db8:abc4::/64", "--gateway=2001:db8:abc4::254", "dualstackbridge")
// Ensure the network was created
assertNwIsAvailable(c, "dualstackbridge")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "--ip", "172.28.100.20", "--ip6", "2001:db8:abc2::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=second", "--ip", "172.28.100.21", "--ip6", "2001:db8:abc2::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackbridge
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackbridge
ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address second to first
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address second to first
c.Skip("Temporarily skipping while invesitigating sporadic v6 CI issues")
_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=third", "--ip", "172.28.102.20", "--ip6", "2001:db8:abc4::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=fourth", "--ip", "172.28.102.21", "--ip6", "2001:db8:abc4::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackbridge
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackbridge
ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// Inspect the v4 gateway to ensure the proper default GW was assigned
ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.Gateway")
c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.100.1")
// Inspect the v6 gateway to ensure the proper default GW was assigned
ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway")
c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc2::1")
// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.Gateway")
c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.102.254")
// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway")
c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc4::254")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L2 network and validate connectivity within the subnets, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.200.0/24", "--subnet=172.28.202.0/24", "--gateway=172.28.202.254",
"--subnet=2001:db8:abc8::/64", "--subnet=2001:db8:abc6::/64", "--gateway=2001:db8:abc6::254", "dualstackl2")
// Ensure the network was created
assertNwIsAvailable(c, "dualstackl2")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.200.0/24 and 2001:db8:abc8::/64
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=first", "--ip", "172.28.200.20", "--ip6", "2001:db8:abc8::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "--ip", "172.28.200.21", "--ip6", "2001:db8:abc8::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackl2
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackl2
ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address second to first
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address second to first
_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.202.0/24 and 2001:db8:abc6::/64
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=third", "--ip", "172.28.202.20", "--ip6", "2001:db8:abc6::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=fourth", "--ip", "172.28.202.21", "--ip6", "2001:db8:abc6::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackl2
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackl2
ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// Inspect the v4 gateway to ensure the proper default GW was assigned
ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.Gateway")
c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.200.1")
// Inspect the v6 gateway to ensure the proper default GW was assigned
ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPv6Gateway")
c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc8::1")
// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.Gateway")
c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.202.254")
// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPv6Gateway")
c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc6::254")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L3 network and validate connectivity between all four containers per L3 mode
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, IPv6, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.10.0/24", "--subnet=172.28.12.0/24", "--gateway=172.28.12.254",
"--subnet=2001:db8:abc9::/64", "--subnet=2001:db8:abc7::/64", "--gateway=2001:db8:abc7::254", "-o", "ipvlan_mode=l3", "dualstackl3")
// Ensure the network was created
assertNwIsAvailable(c, "dualstackl3")
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.10.0/24 and 2001:db8:abc9::/64
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=first", "--ip", "172.28.10.20", "--ip6", "2001:db8:abc9::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=second", "--ip", "172.28.10.21", "--ip6", "2001:db8:abc9::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackl3
ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackl3
ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address second to first
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address second to first
_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.12.0/24 and 2001:db8:abc7::/64
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "--ip", "172.28.12.20", "--ip6", "2001:db8:abc7::20", "busybox", "top")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=fourth", "--ip", "172.28.12.21", "--ip6", "2001:db8:abc7::21", "busybox", "top")
// Inspect and store the v4 address from specified container on the network dualstackl3
ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackl3
ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// Inspect and store the v4 address from specified container on the network dualstackl3
ip = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.IPAddress")
// Inspect and store the v6 address from specified container on the network dualstackl3
ip6 = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
// Verify connectivity across disparate subnets which is unique to L3 mode only
_, _, err = dockerCmdWithError("exec", "third", "ping", "-c", "1", strings.TrimSpace(ip))
c.Assert(err, check.IsNil)
_, _, err = dockerCmdWithError("exec", "third", "ping6", "-c", "1", strings.TrimSpace(ip6))
c.Assert(err, check.IsNil)
// Inspect the v4 gateway to ensure no next hop is assigned in L3 mode
ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.Gateway")
c.Assert(strings.TrimSpace(ip4gw), check.Equals, "")
// Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled
ip6gw := inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPv6Gateway")
c.Assert(strings.TrimSpace(ip6gw), check.Equals, "")
}
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
// Ensure the default gateways, next-hops and default dev devices are properly set
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.130.0/24",
"--subnet=2001:db8:abca::/64", "--gateway=2001:db8:abca::254", "-o", "macvlan_mode=bridge", "dualstackbridge")
assertNwIsAvailable(c, "dualstackbridge")
dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "busybox", "top")
// Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet
out, _, err := dockerCmdWithError("exec", "first", "ip", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default via 172.28.130.1 dev eth0")
// Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop
out, _, err = dockerCmdWithError("exec", "first", "ip", "-6", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default via 2001:db8:abca::254 dev eth0")
// Verify ipvlan l2 mode sets the proper default gateway routes via netlink
// for either an explicitly set route by the user or inferred via default IPAM
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.140.0/24", "--gateway=172.28.140.254",
"--subnet=2001:db8:abcb::/64", "-o", "ipvlan_mode=l2", "dualstackl2")
assertNwIsAvailable(c, "dualstackl2")
dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "busybox", "top")
// Validate ipvlan l2 mode defaults gateway sets the default IPAM next-hop inferred from the subnet
out, _, err = dockerCmdWithError("exec", "second", "ip", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default via 172.28.140.254 dev eth0")
// Validate ipvlan l2 mode sets the v6 gateway to the user specified default gateway/next-hop
out, _, err = dockerCmdWithError("exec", "second", "ip", "-6", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default via 2001:db8:abcb::1 dev eth0")
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.160.0/24", "--gateway=172.28.160.254",
"--subnet=2001:db8:abcd::/64", "--gateway=2001:db8:abcd::254", "-o", "ipvlan_mode=l3", "dualstackl3")
assertNwIsAvailable(c, "dualstackl3")
dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "busybox", "top")
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
out, _, err = dockerCmdWithError("exec", "third", "ip", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default dev eth0")
// Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops
out, _, err = dockerCmdWithError("exec", "third", "ip", "-6", "route")
c.Assert(err, check.IsNil)
c.Assert(out, checker.Contains, "default dev eth0")
}
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
// macvlan bridge mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "dm-nil-parent")
assertNwIsAvailable(c, "dm-nil-parent")
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
// macvlan bridge mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--internal", "dm-internal")
assertNwIsAvailable(c, "dm-internal")
nr := getNetworkResource(c, "dm-internal")
c.Assert(nr.Internal, checker.True)
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
// ipvlan l2 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "di-nil-parent")
assertNwIsAvailable(c, "di-nil-parent")
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
// ipvlan l2 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--internal", "di-internal")
assertNwIsAvailable(c, "di-internal")
nr := getNetworkResource(c, "di-internal")
c.Assert(nr.Internal, checker.True)
// start two containers on the same subnet
dockerCmd(c, "run", "-d", "--net=di-internal", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=di-internal", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
// ipvlan l3 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "di-nil-parent-l3")
assertNwIsAvailable(c, "di-nil-parent-l3")
// start two containers on separate subnets
dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-nil-parent-l3", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-nil-parent-l3", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
// ipvlan l3 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "--internal", "di-internal-l3")
assertNwIsAvailable(c, "di-internal-l3")
nr := getNetworkResource(c, "di-internal-l3")
c.Assert(nr.Internal, checker.True)
// start two containers on separate subnets
dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-internal-l3", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-internal-l3", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// access outside of the network should fail
result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
// intra-network communications should succeed
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}
func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-parent-exists"
out, err := createMasterDummy(c, "dm-dummy0")
//out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge")
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network using an existing parent interface
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0", netName)
assertNwIsAvailable(c, netName)
// delete the network while preserving the parent link
dockerCmd(c, "network", "rm", netName)
assertNwNotAvailable(c, netName)
// verify the network delete did not delete the predefined link
out, err = linkExists(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))
deleteInterface(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))
}
func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-subinterface"
out, err := createMasterDummy(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))
out, err = createVlanInterface(c, "dm-dummy0", "dm-dummy0.20", "20")
c.Assert(err, check.IsNil, check.Commentf(out))
// create a network using an existing parent interface
dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.20", netName)
assertNwIsAvailable(c, netName)
// start containers on 802.1q tagged '-o parent' sub-interface
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=second", "busybox", "top")
c.Assert(waitRun("second"), check.IsNil)
// verify containers can communicate
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
// remove the containers
dockerCmd(c, "rm", "-f", "first")
dockerCmd(c, "rm", "-f", "second")
// delete the network while preserving the parent link
dockerCmd(c, "network", "rm", netName)
assertNwNotAvailable(c, netName)
// verify the network delete did not delete the predefined sub-interface
out, err = linkExists(c, "dm-dummy0.20")
c.Assert(err, check.IsNil, check.Commentf(out))
// delete the parent interface which also collects the slave
deleteInterface(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))
}
func createMasterDummy(c *check.C, master string) (string, error) {
// ip link add <dummy_name> type dummy
args := []string{"link", "add", master, "type", "dummy"}
ipLinkCmd := exec.Command("ip", args...)
out, _, err := runCommandWithOutput(ipLinkCmd)
if err != nil {
return out, err
}
// ip link set dummy_name up
args = []string{"link", "set", master, "up"}
ipLinkCmd = exec.Command("ip", args...)
out, _, err = runCommandWithOutput(ipLinkCmd)
if err != nil {
return out, err
}
return out, err
}
func createVlanInterface(c *check.C, master, slave, id string) (string, error) {
// ip link add link <master> name <master>.<VID> type vlan id <VID>
args := []string{"link", "add", "link", master, "name", slave, "type", "vlan", "id", id}
ipLinkCmd := exec.Command("ip", args...)
out, _, err := runCommandWithOutput(ipLinkCmd)
if err != nil {
return out, err
}
// ip link set <sub_interface_name> up
args = []string{"link", "set", slave, "up"}
ipLinkCmd = exec.Command("ip", args...)
out, _, err = runCommandWithOutput(ipLinkCmd)
if err != nil {
return out, err
}
return out, err
}
func linkExists(c *check.C, master string) (string, error) {
// verify the specified link exists, ip link show <link_name>
args := []string{"link", "show", master}
ipLinkCmd := exec.Command("ip", args...)
out, _, err := runCommandWithOutput(ipLinkCmd)
if err != nil {
return out, err
}
return out, err
}