github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/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, MacvlanKernelSupport, NotUserNamespace, NotArm) 161 dockerCmd(c, "network", "create", "--driver=macvlan", "--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 _, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6)) 179 c.Assert(err, check.IsNil) 180 181 // 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 182 dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=third", "--ip", "172.28.102.20", "--ip6", "2001:db8:abc4::20", "busybox", "top") 183 dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=fourth", "--ip", "172.28.102.21", "--ip6", "2001:db8:abc4::21", "busybox", "top") 184 185 // Inspect and store the v4 address from specified container on the network dualstackbridge 186 ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPAddress") 187 // Inspect and store the v6 address from specified container on the network dualstackbridge 188 ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.GlobalIPv6Address") 189 190 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 191 _, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip)) 192 c.Assert(err, check.IsNil) 193 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 194 _, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6)) 195 c.Assert(err, check.IsNil) 196 197 // Inspect the v4 gateway to ensure the proper default GW was assigned 198 ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.Gateway") 199 c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.100.1") 200 // Inspect the v6 gateway to ensure the proper default GW was assigned 201 ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway") 202 c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc2::1") 203 204 // Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned 205 ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.Gateway") 206 c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.102.254") 207 // Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned 208 ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackbridge.IPv6Gateway") 209 c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc4::254") 210 } 211 212 func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) { 213 // create a dual stack multi-subnet Ipvlan L2 network and validate connectivity within the subnets, two on each subnet 214 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 215 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.200.0/24", "--subnet=172.28.202.0/24", "--gateway=172.28.202.254", 216 "--subnet=2001:db8:abc8::/64", "--subnet=2001:db8:abc6::/64", "--gateway=2001:db8:abc6::254", "dualstackl2") 217 // Ensure the network was created 218 assertNwIsAvailable(c, "dualstackl2") 219 // 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 220 dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=first", "--ip", "172.28.200.20", "--ip6", "2001:db8:abc8::20", "busybox", "top") 221 dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "--ip", "172.28.200.21", "--ip6", "2001:db8:abc8::21", "busybox", "top") 222 223 // Inspect and store the v4 address from specified container on the network dualstackl2 224 ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPAddress") 225 // Inspect and store the v6 address from specified container on the network dualstackl2 226 ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address") 227 228 // verify ipv4 connectivity to the explicit --ipv address second to first 229 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip)) 230 c.Assert(err, check.IsNil) 231 // verify ipv6 connectivity to the explicit --ipv6 address second to first 232 _, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6)) 233 c.Assert(err, check.IsNil) 234 235 // 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 236 dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=third", "--ip", "172.28.202.20", "--ip6", "2001:db8:abc6::20", "busybox", "top") 237 dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=fourth", "--ip", "172.28.202.21", "--ip6", "2001:db8:abc6::21", "busybox", "top") 238 239 // Inspect and store the v4 address from specified container on the network dualstackl2 240 ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPAddress") 241 // Inspect and store the v6 address from specified container on the network dualstackl2 242 ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.GlobalIPv6Address") 243 244 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 245 _, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip)) 246 c.Assert(err, check.IsNil) 247 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 248 _, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6)) 249 c.Assert(err, check.IsNil) 250 251 // Inspect the v4 gateway to ensure the proper default GW was assigned 252 ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.Gateway") 253 c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.200.1") 254 // Inspect the v6 gateway to ensure the proper default GW was assigned 255 ip6gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl2.IPv6Gateway") 256 c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc8::1") 257 258 // Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned 259 ip4gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.Gateway") 260 c.Assert(strings.TrimSpace(ip4gw), check.Equals, "172.28.202.254") 261 // Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned 262 ip6gw = inspectField(c, "third", "NetworkSettings.Networks.dualstackl2.IPv6Gateway") 263 c.Assert(strings.TrimSpace(ip6gw), check.Equals, "2001:db8:abc6::254") 264 } 265 266 func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) { 267 // create a dual stack multi-subnet Ipvlan L3 network and validate connectivity between all four containers per L3 mode 268 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 269 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.10.0/24", "--subnet=172.28.12.0/24", "--gateway=172.28.12.254", 270 "--subnet=2001:db8:abc9::/64", "--subnet=2001:db8:abc7::/64", "--gateway=2001:db8:abc7::254", "-o", "ipvlan_mode=l3", "dualstackl3") 271 // Ensure the network was created 272 assertNwIsAvailable(c, "dualstackl3") 273 274 // 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 275 dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=first", "--ip", "172.28.10.20", "--ip6", "2001:db8:abc9::20", "busybox", "top") 276 dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=second", "--ip", "172.28.10.21", "--ip6", "2001:db8:abc9::21", "busybox", "top") 277 278 // Inspect and store the v4 address from specified container on the network dualstackl3 279 ip := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.IPAddress") 280 // Inspect and store the v6 address from specified container on the network dualstackl3 281 ip6 := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address") 282 283 // verify ipv4 connectivity to the explicit --ipv address second to first 284 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", strings.TrimSpace(ip)) 285 c.Assert(err, check.IsNil) 286 // verify ipv6 connectivity to the explicit --ipv6 address second to first 287 _, _, err = dockerCmdWithError("exec", "second", "ping6", "-c", "1", strings.TrimSpace(ip6)) 288 c.Assert(err, check.IsNil) 289 290 // 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 291 dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "--ip", "172.28.12.20", "--ip6", "2001:db8:abc7::20", "busybox", "top") 292 dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=fourth", "--ip", "172.28.12.21", "--ip6", "2001:db8:abc7::21", "busybox", "top") 293 294 // Inspect and store the v4 address from specified container on the network dualstackl3 295 ip = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPAddress") 296 // Inspect and store the v6 address from specified container on the network dualstackl3 297 ip6 = inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address") 298 299 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 300 _, _, err = dockerCmdWithError("exec", "fourth", "ping", "-c", "1", strings.TrimSpace(ip)) 301 c.Assert(err, check.IsNil) 302 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 303 _, _, err = dockerCmdWithError("exec", "fourth", "ping6", "-c", "1", strings.TrimSpace(ip6)) 304 c.Assert(err, check.IsNil) 305 306 // Inspect and store the v4 address from specified container on the network dualstackl3 307 ip = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.IPAddress") 308 // Inspect and store the v6 address from specified container on the network dualstackl3 309 ip6 = inspectField(c, "second", "NetworkSettings.Networks.dualstackl3.GlobalIPv6Address") 310 311 // Verify connectivity across disparate subnets which is unique to L3 mode only 312 _, _, err = dockerCmdWithError("exec", "third", "ping", "-c", "1", strings.TrimSpace(ip)) 313 c.Assert(err, check.IsNil) 314 _, _, err = dockerCmdWithError("exec", "third", "ping6", "-c", "1", strings.TrimSpace(ip6)) 315 c.Assert(err, check.IsNil) 316 317 // Inspect the v4 gateway to ensure no next hop is assigned in L3 mode 318 ip4gw := inspectField(c, "first", "NetworkSettings.Networks.dualstackl3.Gateway") 319 c.Assert(strings.TrimSpace(ip4gw), check.Equals, "") 320 // Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled 321 ip6gw := inspectField(c, "third", "NetworkSettings.Networks.dualstackl3.IPv6Gateway") 322 c.Assert(strings.TrimSpace(ip6gw), check.Equals, "") 323 } 324 325 func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) { 326 // Ensure the default gateways, next-hops and default dev devices are properly set 327 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 328 dockerCmd(c, "network", "create", "--driver=macvlan", "--subnet=172.28.130.0/24", 329 "--subnet=2001:db8:abca::/64", "--gateway=2001:db8:abca::254", "-o", "macvlan_mode=bridge", "dualstackbridge") 330 assertNwIsAvailable(c, "dualstackbridge") 331 dockerCmd(c, "run", "-d", "--net=dualstackbridge", "--name=first", "busybox", "top") 332 // Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet 333 out, _, err := dockerCmdWithError("exec", "first", "ip", "route") 334 c.Assert(err, check.IsNil) 335 c.Assert(out, checker.Contains, "default via 172.28.130.1 dev eth0") 336 // Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop 337 out, _, err = dockerCmdWithError("exec", "first", "ip", "-6", "route") 338 c.Assert(err, check.IsNil) 339 c.Assert(out, checker.Contains, "default via 2001:db8:abca::254 dev eth0") 340 341 // Verify ipvlan l2 mode sets the proper default gateway routes via netlink 342 // for either an explicitly set route by the user or inferred via default IPAM 343 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.140.0/24", "--gateway=172.28.140.254", 344 "--subnet=2001:db8:abcb::/64", "-o", "ipvlan_mode=l2", "dualstackl2") 345 assertNwIsAvailable(c, "dualstackl2") 346 dockerCmd(c, "run", "-d", "--net=dualstackl2", "--name=second", "busybox", "top") 347 // Validate ipvlan l2 mode defaults gateway sets the default IPAM next-hop inferred from the subnet 348 out, _, err = dockerCmdWithError("exec", "second", "ip", "route") 349 c.Assert(err, check.IsNil) 350 c.Assert(out, checker.Contains, "default via 172.28.140.254 dev eth0") 351 // Validate ipvlan l2 mode sets the v6 gateway to the user specified default gateway/next-hop 352 out, _, err = dockerCmdWithError("exec", "second", "ip", "-6", "route") 353 c.Assert(err, check.IsNil) 354 c.Assert(out, checker.Contains, "default via 2001:db8:abcb::1 dev eth0") 355 356 // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops 357 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.160.0/24", "--gateway=172.28.160.254", 358 "--subnet=2001:db8:abcd::/64", "--gateway=2001:db8:abcd::254", "-o", "ipvlan_mode=l3", "dualstackl3") 359 assertNwIsAvailable(c, "dualstackl3") 360 dockerCmd(c, "run", "-d", "--net=dualstackl3", "--name=third", "busybox", "top") 361 // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops 362 out, _, err = dockerCmdWithError("exec", "third", "ip", "route") 363 c.Assert(err, check.IsNil) 364 c.Assert(out, checker.Contains, "default dev eth0") 365 // Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops 366 out, _, err = dockerCmdWithError("exec", "third", "ip", "-6", "route") 367 c.Assert(err, check.IsNil) 368 c.Assert(out, checker.Contains, "default dev eth0") 369 } 370 371 func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) { 372 // macvlan bridge mode - dummy parent interface is provisioned dynamically 373 testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm) 374 dockerCmd(c, "network", "create", "--driver=macvlan", "dm-nil-parent") 375 assertNwIsAvailable(c, "dm-nil-parent") 376 377 // start two containers on the same subnet 378 dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=first", "busybox", "top") 379 c.Assert(waitRun("first"), check.IsNil) 380 dockerCmd(c, "run", "-d", "--net=dm-nil-parent", "--name=second", "busybox", "top") 381 c.Assert(waitRun("second"), check.IsNil) 382 383 // intra-network communications should succeed 384 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 385 c.Assert(err, check.IsNil) 386 } 387 388 func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) { 389 // macvlan bridge mode --internal containers can communicate inside the network but not externally 390 testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm) 391 dockerCmd(c, "network", "create", "--driver=macvlan", "--internal", "dm-internal") 392 assertNwIsAvailable(c, "dm-internal") 393 nr := getNetworkResource(c, "dm-internal") 394 c.Assert(nr.Internal, checker.True) 395 396 // start two containers on the same subnet 397 dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=first", "busybox", "top") 398 c.Assert(waitRun("first"), check.IsNil) 399 dockerCmd(c, "run", "-d", "--net=dm-internal", "--name=second", "busybox", "top") 400 c.Assert(waitRun("second"), check.IsNil) 401 402 // access outside of the network should fail 403 _, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8") 404 c.Assert(err, check.NotNil) 405 // intra-network communications should succeed 406 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 407 c.Assert(err, check.IsNil) 408 } 409 410 func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) { 411 // ipvlan l2 mode - dummy parent interface is provisioned dynamically 412 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 413 dockerCmd(c, "network", "create", "--driver=ipvlan", "di-nil-parent") 414 assertNwIsAvailable(c, "di-nil-parent") 415 416 // start two containers on the same subnet 417 dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=first", "busybox", "top") 418 c.Assert(waitRun("first"), check.IsNil) 419 dockerCmd(c, "run", "-d", "--net=di-nil-parent", "--name=second", "busybox", "top") 420 c.Assert(waitRun("second"), check.IsNil) 421 422 // intra-network communications should succeed 423 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 424 c.Assert(err, check.IsNil) 425 } 426 427 func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) { 428 // ipvlan l2 mode --internal containers can communicate inside the network but not externally 429 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 430 dockerCmd(c, "network", "create", "--driver=ipvlan", "--internal", "di-internal") 431 assertNwIsAvailable(c, "di-internal") 432 nr := getNetworkResource(c, "di-internal") 433 c.Assert(nr.Internal, checker.True) 434 435 // start two containers on the same subnet 436 dockerCmd(c, "run", "-d", "--net=di-internal", "--name=first", "busybox", "top") 437 c.Assert(waitRun("first"), check.IsNil) 438 dockerCmd(c, "run", "-d", "--net=di-internal", "--name=second", "busybox", "top") 439 c.Assert(waitRun("second"), check.IsNil) 440 441 // access outside of the network should fail 442 _, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8") 443 c.Assert(err, check.NotNil) 444 // intra-network communications should succeed 445 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 446 c.Assert(err, check.IsNil) 447 } 448 449 func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) { 450 // ipvlan l3 mode - dummy parent interface is provisioned dynamically 451 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 452 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24", 453 "--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "di-nil-parent-l3") 454 assertNwIsAvailable(c, "di-nil-parent-l3") 455 456 // start two containers on separate subnets 457 dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-nil-parent-l3", "--name=first", "busybox", "top") 458 c.Assert(waitRun("first"), check.IsNil) 459 dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-nil-parent-l3", "--name=second", "busybox", "top") 460 c.Assert(waitRun("second"), check.IsNil) 461 462 // intra-network communications should succeed 463 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 464 c.Assert(err, check.IsNil) 465 } 466 467 func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) { 468 // ipvlan l3 mode --internal containers can communicate inside the network but not externally 469 testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm) 470 dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24", 471 "--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "--internal", "di-internal-l3") 472 assertNwIsAvailable(c, "di-internal-l3") 473 nr := getNetworkResource(c, "di-internal-l3") 474 c.Assert(nr.Internal, checker.True) 475 476 // start two containers on separate subnets 477 dockerCmd(c, "run", "-d", "--ip=172.28.220.10", "--net=di-internal-l3", "--name=first", "busybox", "top") 478 c.Assert(waitRun("first"), check.IsNil) 479 dockerCmd(c, "run", "-d", "--ip=172.28.230.10", "--net=di-internal-l3", "--name=second", "busybox", "top") 480 c.Assert(waitRun("second"), check.IsNil) 481 482 // access outside of the network should fail 483 _, _, err := dockerCmdWithTimeout(time.Second, "exec", "first", "ping", "-c", "1", "-w", "1", "8.8.8.8") 484 c.Assert(err, check.NotNil) 485 // intra-network communications should succeed 486 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 487 c.Assert(err, check.IsNil) 488 } 489 490 func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) { 491 // macvlan bridge mode - empty parent interface containers can reach each other internally but not externally 492 testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm) 493 netName := "dm-parent-exists" 494 out, err := createMasterDummy(c, "dm-dummy0") 495 //out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge") 496 c.Assert(err, check.IsNil, check.Commentf(out)) 497 // create a network using an existing parent interface 498 dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0", netName) 499 assertNwIsAvailable(c, netName) 500 // delete the network while preserving the parent link 501 dockerCmd(c, "network", "rm", netName) 502 assertNwNotAvailable(c, netName) 503 // verify the network delete did not delete the predefined link 504 out, err = linkExists(c, "dm-dummy0") 505 c.Assert(err, check.IsNil, check.Commentf(out)) 506 deleteInterface(c, "dm-dummy0") 507 c.Assert(err, check.IsNil, check.Commentf(out)) 508 } 509 510 func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) { 511 // macvlan bridge mode - empty parent interface containers can reach each other internally but not externally 512 testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm) 513 netName := "dm-subinterface" 514 out, err := createMasterDummy(c, "dm-dummy0") 515 c.Assert(err, check.IsNil, check.Commentf(out)) 516 out, err = createVlanInterface(c, "dm-dummy0", "dm-dummy0.20", "20") 517 c.Assert(err, check.IsNil, check.Commentf(out)) 518 // create a network using an existing parent interface 519 dockerCmd(c, "network", "create", "--driver=macvlan", "-o", "parent=dm-dummy0.20", netName) 520 assertNwIsAvailable(c, netName) 521 522 // start containers on 802.1q tagged '-o parent' sub-interface 523 dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=first", "busybox", "top") 524 c.Assert(waitRun("first"), check.IsNil) 525 dockerCmd(c, "run", "-d", "--net=dm-subinterface", "--name=second", "busybox", "top") 526 c.Assert(waitRun("second"), check.IsNil) 527 // verify containers can communicate 528 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 529 c.Assert(err, check.IsNil) 530 531 // remove the containers 532 dockerCmd(c, "rm", "-f", "first") 533 dockerCmd(c, "rm", "-f", "second") 534 // delete the network while preserving the parent link 535 dockerCmd(c, "network", "rm", netName) 536 assertNwNotAvailable(c, netName) 537 // verify the network delete did not delete the predefined sub-interface 538 out, err = linkExists(c, "dm-dummy0.20") 539 c.Assert(err, check.IsNil, check.Commentf(out)) 540 // delete the parent interface which also collects the slave 541 deleteInterface(c, "dm-dummy0") 542 c.Assert(err, check.IsNil, check.Commentf(out)) 543 } 544 545 func createMasterDummy(c *check.C, master string) (string, error) { 546 // ip link add <dummy_name> type dummy 547 args := []string{"link", "add", master, "type", "dummy"} 548 ipLinkCmd := exec.Command("ip", args...) 549 out, _, err := runCommandWithOutput(ipLinkCmd) 550 if err != nil { 551 return out, err 552 } 553 // ip link set dummy_name up 554 args = []string{"link", "set", master, "up"} 555 ipLinkCmd = exec.Command("ip", args...) 556 out, _, err = runCommandWithOutput(ipLinkCmd) 557 if err != nil { 558 return out, err 559 } 560 return out, err 561 } 562 563 func createVlanInterface(c *check.C, master, slave, id string) (string, error) { 564 // ip link add link <master> name <master>.<VID> type vlan id <VID> 565 args := []string{"link", "add", "link", master, "name", slave, "type", "vlan", "id", id} 566 ipLinkCmd := exec.Command("ip", args...) 567 out, _, err := runCommandWithOutput(ipLinkCmd) 568 if err != nil { 569 return out, err 570 } 571 // ip link set <sub_interface_name> up 572 args = []string{"link", "set", slave, "up"} 573 ipLinkCmd = exec.Command("ip", args...) 574 out, _, err = runCommandWithOutput(ipLinkCmd) 575 if err != nil { 576 return out, err 577 } 578 return out, err 579 } 580 581 func linkExists(c *check.C, master string) (string, error) { 582 // verify the specified link exists, ip link show <link_name> 583 args := []string{"link", "show", master} 584 ipLinkCmd := exec.Command("ip", args...) 585 out, _, err := runCommandWithOutput(ipLinkCmd) 586 if err != nil { 587 return out, err 588 } 589 return out, err 590 }