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