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