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