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