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