github.com/nullne/docker@v1.13.0-rc1/integration-cli/docker_experimental_network_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"os/exec"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/docker/docker/pkg/integration/checker"
    11  	icmd "github.com/docker/docker/pkg/integration/cmd"
    12  	"github.com/docker/docker/pkg/parsers/kernel"
    13  	"github.com/go-check/check"
    14  )
    15  
    16  var (
    17  	MacvlanKernelSupport = testRequirement{
    18  		func() bool {
    19  			const macvlanKernelVer = 3 // minimum macvlan kernel support
    20  			const macvlanMajorVer = 9  // minimum macvlan major kernel support
    21  			kv, err := kernel.GetKernelVersion()
    22  			if err != nil {
    23  				return false
    24  			}
    25  			// ensure Kernel version is >= v3.9 for macvlan support
    26  			if kv.Kernel < macvlanKernelVer || (kv.Kernel == macvlanKernelVer && kv.Major < macvlanMajorVer) {
    27  				return false
    28  			}
    29  			return true
    30  		},
    31  		"kernel version failed to meet the minimum macvlan kernel requirement of 3.9",
    32  	}
    33  	IpvlanKernelSupport = testRequirement{
    34  		func() bool {
    35  			const ipvlanKernelVer = 4 // minimum ipvlan kernel support
    36  			const ipvlanMajorVer = 2  // minimum ipvlan major kernel support
    37  			kv, err := kernel.GetKernelVersion()
    38  			if err != nil {
    39  				return false
    40  			}
    41  			// ensure Kernel version is >= v4.2 for ipvlan support
    42  			if kv.Kernel < ipvlanKernelVer || (kv.Kernel == ipvlanKernelVer && kv.Major < ipvlanMajorVer) {
    43  				return false
    44  			}
    45  			return true
    46  		},
    47  		"kernel version failed to meet the minimum ipvlan kernel requirement of 4.0.0",
    48  	}
    49  )
    50  
    51  func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
    52  	// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
    53  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
    54  
    55  	// master dummy interface 'dm' abbreviation represents 'docker macvlan'
    56  	master := "dm-dummy0"
    57  	// simulate the master link the vlan tagged subinterface parent link will use
    58  	out, err := createMasterDummy(c, master)
    59  	c.Assert(err, check.IsNil, check.Commentf(out))
    60  	// create a network specifying the desired sub-interface name
    61  	dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.60", "dm-persist")
    62  	assertNwIsAvailable(c, "dm-persist")
    63  	// Restart docker daemon to test the config has persisted to disk
    64  	s.d.Restart()
    65  	// verify network is recreated from persistence
    66  	assertNwIsAvailable(c, "dm-persist")
    67  	// cleanup the master interface that also collects the slave dev
    68  	deleteInterface(c, "dm-dummy0")
    69  }
    70  
    71  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
    72  	// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
    73  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
    74  	// master dummy interface 'di' notation represent 'docker ipvlan'
    75  	master := "di-dummy0"
    76  	// simulate the master link the vlan tagged subinterface parent link will use
    77  	out, err := createMasterDummy(c, master)
    78  	c.Assert(err, check.IsNil, check.Commentf(out))
    79  	// create a network specifying the desired sub-interface name
    80  	dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.70", "di-persist")
    81  	assertNwIsAvailable(c, "di-persist")
    82  	// Restart docker daemon to test the config has persisted to disk
    83  	s.d.Restart()
    84  	// verify network is recreated from persistence
    85  	assertNwIsAvailable(c, "di-persist")
    86  	// cleanup the master interface that also collects the slave dev
    87  	deleteInterface(c, "di-dummy0")
    88  }
    89  
    90  func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
    91  	// verify the driver automatically provisions the 802.1q link (dm-dummy0.50)
    92  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
    93  	// master dummy interface 'dm' abbreviation represents 'docker macvlan'
    94  	master := "dm-dummy0"
    95  	// simulate the master link the vlan tagged subinterface parent link will use
    96  	out, err := createMasterDummy(c, master)
    97  	c.Assert(err, check.IsNil, check.Commentf(out))
    98  	// create a network specifying the desired sub-interface name
    99  	dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.50", "dm-subinterface")
   100  	assertNwIsAvailable(c, "dm-subinterface")
   101  	// cleanup the master interface which also collects the slave dev
   102  	deleteInterface(c, "dm-dummy0")
   103  }
   104  
   105  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
   106  	// verify the driver automatically provisions the 802.1q link (di-dummy0.50)
   107  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   108  	// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
   109  	master := "di-dummy0"
   110  	// simulate the master link the vlan tagged subinterface parent link will use
   111  	out, err := createMasterDummy(c, master)
   112  	c.Assert(err, check.IsNil, check.Commentf(out))
   113  	// create a network specifying the desired sub-interface name
   114  	dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.60", "di-subinterface")
   115  	assertNwIsAvailable(c, "di-subinterface")
   116  	// cleanup the master interface which also collects the slave dev
   117  	deleteInterface(c, "di-dummy0")
   118  }
   119  
   120  func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
   121  	// verify the same parent interface cannot be used if already in use by an existing network
   122  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   123  	// master dummy interface 'dm' abbreviation represents 'docker macvlan'
   124  	master := "dm-dummy0"
   125  	out, err := createMasterDummy(c, master)
   126  	c.Assert(err, check.IsNil, check.Commentf(out))
   127  	out, err = createVlanInterface(c, master, "dm-dummy0.40", "40")
   128  	c.Assert(err, check.IsNil, check.Commentf(out))
   129  	// create a network using an existing parent interface
   130  	dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-subinterface")
   131  	assertNwIsAvailable(c, "dm-subinterface")
   132  	// attempt to create another network using the same parent iface that should fail
   133  	out, _, err = dockerCmdWithError("network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.40", "dm-parent-net-overlap")
   134  	// verify that the overlap returns an error
   135  	c.Assert(err, check.NotNil)
   136  	// cleanup the master interface which also collects the slave dev
   137  	deleteInterface(c, "dm-dummy0")
   138  }
   139  
   140  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
   141  	// verify the same parent interface cannot be used if already in use by an existing network
   142  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   143  	// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
   144  	master := "di-dummy0"
   145  	out, err := createMasterDummy(c, master)
   146  	c.Assert(err, check.IsNil, check.Commentf(out))
   147  	out, err = createVlanInterface(c, master, "di-dummy0.30", "30")
   148  	c.Assert(err, check.IsNil, check.Commentf(out))
   149  	// create a network using an existing parent interface
   150  	dockerCmd(c, "network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-subinterface")
   151  	assertNwIsAvailable(c, "di-subinterface")
   152  	// attempt to create another network using the same parent iface that should fail
   153  	out, _, err = dockerCmdWithError("network", "create", "--driver=ipvlan", "-o", "parent=di-dummy0.30", "di-parent-net-overlap")
   154  	// verify that the overlap returns an error
   155  	c.Assert(err, check.NotNil)
   156  	// cleanup the master interface which also collects the slave dev
   157  	deleteInterface(c, "di-dummy0")
   158  }
   159  
   160  func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
   161  	// create a dual stack multi-subnet Macvlan bridge mode network and validate connectivity between four containers, two on each subnet
   162  	testRequires(c, DaemonIsLinux, IPv6, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   163  	dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.100.0/24", "--subnet=172.28.102.0/24", "--gateway=172.28.102.254",
   164  		"--subnet=2001:db8:abc2::/64", "--subnet=2001:db8:abc4::/64", "--gateway=2001:db8:abc4::254", "dualstackbridge")
   165  	// Ensure the network was created
   166  	assertNwIsAvailable(c, "dualstackbridge")
   167  	// 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
   168  	dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "--ip", "172.28.100.20", "--ip6", "2001:db8:abc2::20", "busybox", "top")
   169  	dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=second", "--ip", "172.28.100.21", "--ip6", "2001:db8:abc2::21", "busybox", "top")
   170  
   171  	// Inspect and store the v4 address from specified container on the network dualstackbridge
   172  	ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPAddress")
   173  	// Inspect and store the v6 address from specified container on the network dualstackbridge
   174  	ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.GlobalIPv6Address")
   175  
   176  	// verify ipv4 connectivity to the explicit --ipv address second to first
   177  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
   178  	c.Assert(err, check.IsNil)
   179  	// verify ipv6 connectivity to the explicit --ipv6 address second to first
   180  	c.Skip("Temporarily skipping while invesitigating sporadic v6 CI issues")
   181  	_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
   182  	c.Assert(err, check.IsNil)
   183  
   184  	// 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
   185  	dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=third", "--ip", "172.28.102.20", "--ip6", "2001:db8:abc4::20", "busybox", "top")
   186  	dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=fourth", "--ip", "172.28.102.21", "--ip6", "2001:db8:abc4::21", "busybox", "top")
   187  
   188  	// Inspect and store the v4 address from specified container on the network dualstackbridge
   189  	ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPAddress")
   190  	// Inspect and store the v6 address from specified container on the network dualstackbridge
   191  	ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.GlobalIPv6Address")
   192  
   193  	// verify ipv4 connectivity to the explicit --ipv address from third to fourth
   194  	_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
   195  	c.Assert(err, check.IsNil)
   196  	// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
   197  	_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
   198  	c.Assert(err, check.IsNil)
   199  
   200  	// Inspect the v4 gateway to ensure the proper default GW was assigned
   201  	ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.Gateway")
   202  	c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.100.1")
   203  	// Inspect the v6 gateway to ensure the proper default GW was assigned
   204  	ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway")
   205  	c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc2::1")
   206  
   207  	// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
   208  	ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.Gateway")
   209  	c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.102.254")
   210  	// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
   211  	ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway")
   212  	c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc4::254")
   213  }
   214  
   215  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
   216  	// create a dual stack multi-subnet Ipvlan L2 network and validate connectivity within the subnets, two on each subnet
   217  	testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   218  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.200.0/24", "--subnet=172.28.202.0/24", "--gateway=172.28.202.254",
   219  		"--subnet=2001:db8:abc8::/64", "--subnet=2001:db8:abc6::/64", "--gateway=2001:db8:abc6::254", "dualstackl2")
   220  	// Ensure the network was created
   221  	assertNwIsAvailable(c, "dualstackl2")
   222  	// 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
   223  	dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=first", "--ip", "172.28.200.20", "--ip6", "2001:db8:abc8::20", "busybox", "top")
   224  	dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "--ip", "172.28.200.21", "--ip6", "2001:db8:abc8::21", "busybox", "top")
   225  
   226  	// Inspect and store the v4 address from specified container on the network dualstackl2
   227  	ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPAddress")
   228  	// Inspect and store the v6 address from specified container on the network dualstackl2
   229  	ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address")
   230  
   231  	// verify ipv4 connectivity to the explicit --ipv address second to first
   232  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
   233  	c.Assert(err, check.IsNil)
   234  	// verify ipv6 connectivity to the explicit --ipv6 address second to first
   235  	_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
   236  	c.Assert(err, check.IsNil)
   237  
   238  	// 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
   239  	dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=third", "--ip", "172.28.202.20", "--ip6", "2001:db8:abc6::20", "busybox", "top")
   240  	dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=fourth", "--ip", "172.28.202.21", "--ip6", "2001:db8:abc6::21", "busybox", "top")
   241  
   242  	// Inspect and store the v4 address from specified container on the network dualstackl2
   243  	ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPAddress")
   244  	// Inspect and store the v6 address from specified container on the network dualstackl2
   245  	ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address")
   246  
   247  	// verify ipv4 connectivity to the explicit --ipv address from third to fourth
   248  	_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
   249  	c.Assert(err, check.IsNil)
   250  	// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
   251  	_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
   252  	c.Assert(err, check.IsNil)
   253  
   254  	// Inspect the v4 gateway to ensure the proper default GW was assigned
   255  	ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.Gateway")
   256  	c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.200.1")
   257  	// Inspect the v6 gateway to ensure the proper default GW was assigned
   258  	ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPv6Gateway")
   259  	c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc8::1")
   260  
   261  	// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
   262  	ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.Gateway")
   263  	c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.202.254")
   264  	// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
   265  	ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPv6Gateway")
   266  	c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc6::254")
   267  }
   268  
   269  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
   270  	// create a dual stack multi-subnet Ipvlan L3 network and validate connectivity between all four containers per L3 mode
   271  	testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, IPv6, ExperimentalDaemon)
   272  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.10.0/24", "--subnet=172.28.12.0/24", "--gateway=172.28.12.254",
   273  		"--subnet=2001:db8:abc9::/64", "--subnet=2001:db8:abc7::/64", "--gateway=2001:db8:abc7::254", "-o", "ipvlan_mode=l3", "dualstackl3")
   274  	// Ensure the network was created
   275  	assertNwIsAvailable(c, "dualstackl3")
   276  
   277  	// 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
   278  	dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=first", "--ip", "172.28.10.20", "--ip6", "2001:db8:abc9::20", "busybox", "top")
   279  	dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=second", "--ip", "172.28.10.21", "--ip6", "2001:db8:abc9::21", "busybox", "top")
   280  
   281  	// Inspect and store the v4 address from specified container on the network dualstackl3
   282  	ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.IPAddress")
   283  	// Inspect and store the v6 address from specified container on the network dualstackl3
   284  	ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
   285  
   286  	// verify ipv4 connectivity to the explicit --ipv address second to first
   287  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip))
   288  	c.Assert(err, check.IsNil)
   289  	// verify ipv6 connectivity to the explicit --ipv6 address second to first
   290  	_, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6))
   291  	c.Assert(err, check.IsNil)
   292  
   293  	// 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
   294  	dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "--ip", "172.28.12.20", "--ip6", "2001:db8:abc7::20", "busybox", "top")
   295  	dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=fourth", "--ip", "172.28.12.21", "--ip6", "2001:db8:abc7::21", "busybox", "top")
   296  
   297  	// Inspect and store the v4 address from specified container on the network dualstackl3
   298  	ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPAddress")
   299  	// Inspect and store the v6 address from specified container on the network dualstackl3
   300  	ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
   301  
   302  	// verify ipv4 connectivity to the explicit --ipv address from third to fourth
   303  	_, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip))
   304  	c.Assert(err, check.IsNil)
   305  	// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
   306  	_, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6))
   307  	c.Assert(err, check.IsNil)
   308  
   309  	// Inspect and store the v4 address from specified container on the network dualstackl3
   310  	ip = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.IPAddress")
   311  	// Inspect and store the v6 address from specified container on the network dualstackl3
   312  	ip6 = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address")
   313  
   314  	// Verify connectivity across disparate subnets which is unique to L3 mode only
   315  	_, _, err = dockerCmdWithError("exec", "third", "ping", "-c", "1", strings.TrimSpace(ip))
   316  	c.Assert(err, check.IsNil)
   317  	_, _, err = dockerCmdWithError("exec", "third", "ping6", "-c", "1", strings.TrimSpace(ip6))
   318  	c.Assert(err, check.IsNil)
   319  
   320  	// Inspect the v4 gateway to ensure no next hop is assigned in L3 mode
   321  	ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.Gateway")
   322  	c.Assert(strings.TrimSpace(ip4gw), check.Equals, "")
   323  	// Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled
   324  	ip6gw := inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPv6Gateway")
   325  	c.Assert(strings.TrimSpace(ip6gw), check.Equals, "")
   326  }
   327  
   328  func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
   329  	// Ensure the default gateways, next-hops and default dev devices are properly set
   330  	testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   331  	dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.130.0/24",
   332  		"--subnet=2001:db8:abca::/64", "--gateway=2001:db8:abca::254", "-o", "macvlan_mode=bridge", "dualstackbridge")
   333  	assertNwIsAvailable(c, "dualstackbridge")
   334  	dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "busybox", "top")
   335  	// Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet
   336  	out, _, err := dockerCmdWithError("exec", "first", "ip", "route")
   337  	c.Assert(err, check.IsNil)
   338  	c.Assert(out, checker.Contains, "default via 172.28.130.1 dev eth0")
   339  	// Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop
   340  	out, _, err = dockerCmdWithError("exec", "first", "ip", "-6", "route")
   341  	c.Assert(err, check.IsNil)
   342  	c.Assert(out, checker.Contains, "default via 2001:db8:abca::254 dev eth0")
   343  
   344  	// Verify ipvlan l2 mode sets the proper default gateway routes via netlink
   345  	// for either an explicitly set route by the user or inferred via default IPAM
   346  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.140.0/24", "--gateway=172.28.140.254",
   347  		"--subnet=2001:db8:abcb::/64", "-o", "ipvlan_mode=l2", "dualstackl2")
   348  	assertNwIsAvailable(c, "dualstackl2")
   349  	dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "busybox", "top")
   350  	// Validate ipvlan l2 mode defaults gateway sets the default IPAM next-hop inferred from the subnet
   351  	out, _, err = dockerCmdWithError("exec", "second", "ip", "route")
   352  	c.Assert(err, check.IsNil)
   353  	c.Assert(out, checker.Contains, "default via 172.28.140.254 dev eth0")
   354  	// Validate ipvlan l2 mode sets the v6 gateway to the user specified default gateway/next-hop
   355  	out, _, err = dockerCmdWithError("exec", "second", "ip", "-6", "route")
   356  	c.Assert(err, check.IsNil)
   357  	c.Assert(out, checker.Contains, "default via 2001:db8:abcb::1 dev eth0")
   358  
   359  	// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
   360  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.160.0/24", "--gateway=172.28.160.254",
   361  		"--subnet=2001:db8:abcd::/64", "--gateway=2001:db8:abcd::254", "-o", "ipvlan_mode=l3", "dualstackl3")
   362  	assertNwIsAvailable(c, "dualstackl3")
   363  	dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "busybox", "top")
   364  	// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
   365  	out, _, err = dockerCmdWithError("exec", "third", "ip", "route")
   366  	c.Assert(err, check.IsNil)
   367  	c.Assert(out, checker.Contains, "default dev eth0")
   368  	// Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops
   369  	out, _, err = dockerCmdWithError("exec", "third", "ip", "-6", "route")
   370  	c.Assert(err, check.IsNil)
   371  	c.Assert(out, checker.Contains, "default dev eth0")
   372  }
   373  
   374  func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
   375  	// macvlan bridge mode - dummy parent interface is provisioned dynamically
   376  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   377  	dockerCmd(c, "network", "create", "--driver=macvlan", "dm-nil-parent")
   378  	assertNwIsAvailable(c, "dm-nil-parent")
   379  
   380  	// start two containers on the same subnet
   381  	dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=first", "busybox", "top")
   382  	c.Assert(waitRun("first"), check.IsNil)
   383  	dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=second", "busybox", "top")
   384  	c.Assert(waitRun("second"), check.IsNil)
   385  
   386  	// intra-network communications should succeed
   387  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   388  	c.Assert(err, check.IsNil)
   389  }
   390  
   391  func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
   392  	// macvlan bridge mode --internal containers can communicate inside the network but not externally
   393  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   394  	dockerCmd(c, "network", "create", "--driver=macvlan", "--internal", "dm-internal")
   395  	assertNwIsAvailable(c, "dm-internal")
   396  	nr := getNetworkResource(c, "dm-internal")
   397  	c.Assert(nr.Internal, checker.True)
   398  
   399  	// start two containers on the same subnet
   400  	dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=first", "busybox", "top")
   401  	c.Assert(waitRun("first"), check.IsNil)
   402  	dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=second", "busybox", "top")
   403  	c.Assert(waitRun("second"), check.IsNil)
   404  
   405  	// access outside of the network should fail
   406  	result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
   407  	c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
   408  
   409  	// intra-network communications should succeed
   410  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   411  	c.Assert(err, check.IsNil)
   412  }
   413  
   414  func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
   415  	// ipvlan l2 mode - dummy parent interface is provisioned dynamically
   416  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   417  	dockerCmd(c, "network", "create", "--driver=ipvlan", "di-nil-parent")
   418  	assertNwIsAvailable(c, "di-nil-parent")
   419  
   420  	// start two containers on the same subnet
   421  	dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=first", "busybox", "top")
   422  	c.Assert(waitRun("first"), check.IsNil)
   423  	dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=second", "busybox", "top")
   424  	c.Assert(waitRun("second"), check.IsNil)
   425  
   426  	// intra-network communications should succeed
   427  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   428  	c.Assert(err, check.IsNil)
   429  }
   430  
   431  func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
   432  	// ipvlan l2 mode --internal containers can communicate inside the network but not externally
   433  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   434  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--internal", "di-internal")
   435  	assertNwIsAvailable(c, "di-internal")
   436  	nr := getNetworkResource(c, "di-internal")
   437  	c.Assert(nr.Internal, checker.True)
   438  
   439  	// start two containers on the same subnet
   440  	dockerCmd(c, "run", "-d", "--net=di-internal", "--name=first", "busybox", "top")
   441  	c.Assert(waitRun("first"), check.IsNil)
   442  	dockerCmd(c, "run", "-d", "--net=di-internal", "--name=second", "busybox", "top")
   443  	c.Assert(waitRun("second"), check.IsNil)
   444  
   445  	// access outside of the network should fail
   446  	result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
   447  	c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
   448  	// intra-network communications should succeed
   449  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   450  	c.Assert(err, check.IsNil)
   451  }
   452  
   453  func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
   454  	// ipvlan l3 mode - dummy parent interface is provisioned dynamically
   455  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   456  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
   457  		"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "di-nil-parent-l3")
   458  	assertNwIsAvailable(c, "di-nil-parent-l3")
   459  
   460  	// start two containers on separate subnets
   461  	dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-nil-parent-l3", "--name=first", "busybox", "top")
   462  	c.Assert(waitRun("first"), check.IsNil)
   463  	dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-nil-parent-l3", "--name=second", "busybox", "top")
   464  	c.Assert(waitRun("second"), check.IsNil)
   465  
   466  	// intra-network communications should succeed
   467  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   468  	c.Assert(err, check.IsNil)
   469  }
   470  
   471  func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
   472  	// ipvlan l3 mode --internal containers can communicate inside the network but not externally
   473  	testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   474  	dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
   475  		"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "--internal", "di-internal-l3")
   476  	assertNwIsAvailable(c, "di-internal-l3")
   477  	nr := getNetworkResource(c, "di-internal-l3")
   478  	c.Assert(nr.Internal, checker.True)
   479  
   480  	// start two containers on separate subnets
   481  	dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-internal-l3", "--name=first", "busybox", "top")
   482  	c.Assert(waitRun("first"), check.IsNil)
   483  	dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-internal-l3", "--name=second", "busybox", "top")
   484  	c.Assert(waitRun("second"), check.IsNil)
   485  
   486  	// access outside of the network should fail
   487  	result := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8")
   488  	c.Assert(result, icmd.Matches, icmd.Expected{Timeout: true})
   489  	// intra-network communications should succeed
   490  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   491  	c.Assert(err, check.IsNil)
   492  }
   493  
   494  func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
   495  	// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
   496  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   497  	netName := "dm-parent-exists"
   498  	out, err := createMasterDummy(c, "dm-dummy0")
   499  	//out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge")
   500  	c.Assert(err, check.IsNil, check.Commentf(out))
   501  	// create a network using an existing parent interface
   502  	dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0", netName)
   503  	assertNwIsAvailable(c, netName)
   504  	// delete the network while preserving the parent link
   505  	dockerCmd(c, "network", "rm", netName)
   506  	assertNwNotAvailable(c, netName)
   507  	// verify the network delete did not delete the predefined link
   508  	out, err = linkExists(c, "dm-dummy0")
   509  	c.Assert(err, check.IsNil, check.Commentf(out))
   510  	deleteInterface(c, "dm-dummy0")
   511  	c.Assert(err, check.IsNil, check.Commentf(out))
   512  }
   513  
   514  func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
   515  	// macvlan bridge mode -  empty parent interface containers can reach each other internally but not externally
   516  	testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
   517  	netName := "dm-subinterface"
   518  	out, err := createMasterDummy(c, "dm-dummy0")
   519  	c.Assert(err, check.IsNil, check.Commentf(out))
   520  	out, err = createVlanInterface(c, "dm-dummy0", "dm-dummy0.20", "20")
   521  	c.Assert(err, check.IsNil, check.Commentf(out))
   522  	// create a network using an existing parent interface
   523  	dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.20", netName)
   524  	assertNwIsAvailable(c, netName)
   525  
   526  	// start containers on 802.1q tagged '-o parent' sub-interface
   527  	dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=first", "busybox", "top")
   528  	c.Assert(waitRun("first"), check.IsNil)
   529  	dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=second", "busybox", "top")
   530  	c.Assert(waitRun("second"), check.IsNil)
   531  	// verify containers can communicate
   532  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
   533  	c.Assert(err, check.IsNil)
   534  
   535  	// remove the containers
   536  	dockerCmd(c, "rm", "-f", "first")
   537  	dockerCmd(c, "rm", "-f", "second")
   538  	// delete the network while preserving the parent link
   539  	dockerCmd(c, "network", "rm", netName)
   540  	assertNwNotAvailable(c, netName)
   541  	// verify the network delete did not delete the predefined sub-interface
   542  	out, err = linkExists(c, "dm-dummy0.20")
   543  	c.Assert(err, check.IsNil, check.Commentf(out))
   544  	// delete the parent interface which also collects the slave
   545  	deleteInterface(c, "dm-dummy0")
   546  	c.Assert(err, check.IsNil, check.Commentf(out))
   547  }
   548  
   549  func createMasterDummy(c *check.C, master string) (string, error) {
   550  	// ip link add <dummy_name> type dummy
   551  	args := []string{"link", "add", master, "type", "dummy"}
   552  	ipLinkCmd := exec.Command("ip", args...)
   553  	out, _, err := runCommandWithOutput(ipLinkCmd)
   554  	if err != nil {
   555  		return out, err
   556  	}
   557  	// ip link set dummy_name up
   558  	args = []string{"link", "set", master, "up"}
   559  	ipLinkCmd = exec.Command("ip", args...)
   560  	out, _, err = runCommandWithOutput(ipLinkCmd)
   561  	if err != nil {
   562  		return out, err
   563  	}
   564  	return out, err
   565  }
   566  
   567  func createVlanInterface(c *check.C, master, slave, id string) (string, error) {
   568  	// ip link add link <master> name <master>.<VID> type vlan id <VID>
   569  	args := []string{"link", "add", "link", master, "name", slave, "type", "vlan", "id", id}
   570  	ipLinkCmd := exec.Command("ip", args...)
   571  	out, _, err := runCommandWithOutput(ipLinkCmd)
   572  	if err != nil {
   573  		return out, err
   574  	}
   575  	// ip link set <sub_interface_name> up
   576  	args = []string{"link", "set", slave, "up"}
   577  	ipLinkCmd = exec.Command("ip", args...)
   578  	out, _, err = runCommandWithOutput(ipLinkCmd)
   579  	if err != nil {
   580  		return out, err
   581  	}
   582  	return out, err
   583  }
   584  
   585  func linkExists(c *check.C, master string) (string, error) {
   586  	// verify the specified link exists, ip link show <link_name>
   587  	args := []string{"link", "show", master}
   588  	ipLinkCmd := exec.Command("ip", args...)
   589  	out, _, err := runCommandWithOutput(ipLinkCmd)
   590  	if err != nil {
   591  		return out, err
   592  	}
   593  	return out, err
   594  }