github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration/network/ipvlan/ipvlan_test.go (about) 1 // +build !windows 2 3 package ipvlan 4 5 import ( 6 "context" 7 "strings" 8 "testing" 9 "time" 10 11 dclient "github.com/docker/docker/client" 12 "github.com/docker/docker/integration/internal/container" 13 net "github.com/docker/docker/integration/internal/network" 14 n "github.com/docker/docker/integration/network" 15 "github.com/docker/docker/internal/test/daemon" 16 "gotest.tools/assert" 17 "gotest.tools/skip" 18 ) 19 20 func TestDockerNetworkIpvlanPersistance(t *testing.T) { 21 // verify the driver automatically provisions the 802.1q link (di-dummy0.70) 22 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 23 skip.If(t, testEnv.IsRemoteDaemon) 24 skip.If(t, !ipvlanKernelSupport(), "Kernel doesn't support ipvlan") 25 26 d := daemon.New(t, daemon.WithExperimental) 27 d.StartWithBusybox(t) 28 defer d.Stop(t) 29 30 // master dummy interface 'di' notation represent 'docker ipvlan' 31 master := "di-dummy0" 32 n.CreateMasterDummy(t, master) 33 defer n.DeleteInterface(t, master) 34 35 c := d.NewClientT(t) 36 37 // create a network specifying the desired sub-interface name 38 netName := "di-persist" 39 net.CreateNoError(t, context.Background(), c, netName, 40 net.WithIPvlan("di-dummy0.70", ""), 41 ) 42 43 assert.Check(t, n.IsNetworkAvailable(c, netName)) 44 // Restart docker daemon to test the config has persisted to disk 45 d.Restart(t) 46 assert.Check(t, n.IsNetworkAvailable(c, netName)) 47 } 48 49 func TestDockerNetworkIpvlan(t *testing.T) { 50 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 51 skip.If(t, testEnv.IsRemoteDaemon) 52 skip.If(t, !ipvlanKernelSupport(), "Kernel doesn't support ipvlan") 53 54 for _, tc := range []struct { 55 name string 56 test func(dclient.APIClient) func(*testing.T) 57 }{ 58 { 59 name: "Subinterface", 60 test: testIpvlanSubinterface, 61 }, { 62 name: "OverlapParent", 63 test: testIpvlanOverlapParent, 64 }, { 65 name: "L2NilParent", 66 test: testIpvlanL2NilParent, 67 }, { 68 name: "L2InternalMode", 69 test: testIpvlanL2InternalMode, 70 }, { 71 name: "L3NilParent", 72 test: testIpvlanL3NilParent, 73 }, { 74 name: "L3InternalMode", 75 test: testIpvlanL3InternalMode, 76 }, { 77 name: "L2MultiSubnet", 78 test: testIpvlanL2MultiSubnet, 79 }, { 80 name: "L3MultiSubnet", 81 test: testIpvlanL3MultiSubnet, 82 }, { 83 name: "Addressing", 84 test: testIpvlanAddressing, 85 }, 86 } { 87 d := daemon.New(t, daemon.WithExperimental) 88 d.StartWithBusybox(t) 89 c := d.NewClientT(t) 90 91 t.Run(tc.name, tc.test(c)) 92 93 d.Stop(t) 94 // FIXME(vdemeester) clean network 95 } 96 } 97 98 func testIpvlanSubinterface(client dclient.APIClient) func(*testing.T) { 99 return func(t *testing.T) { 100 master := "di-dummy0" 101 n.CreateMasterDummy(t, master) 102 defer n.DeleteInterface(t, master) 103 104 netName := "di-subinterface" 105 net.CreateNoError(t, context.Background(), client, netName, 106 net.WithIPvlan("di-dummy0.60", ""), 107 ) 108 assert.Check(t, n.IsNetworkAvailable(client, netName)) 109 110 // delete the network while preserving the parent link 111 err := client.NetworkRemove(context.Background(), netName) 112 assert.NilError(t, err) 113 114 assert.Check(t, n.IsNetworkNotAvailable(client, netName)) 115 // verify the network delete did not delete the predefined link 116 n.LinkExists(t, "di-dummy0") 117 } 118 } 119 120 func testIpvlanOverlapParent(client dclient.APIClient) func(*testing.T) { 121 return func(t *testing.T) { 122 // verify the same parent interface cannot be used if already in use by an existing network 123 master := "di-dummy0" 124 parent := master + ".30" 125 n.CreateMasterDummy(t, master) 126 defer n.DeleteInterface(t, master) 127 n.CreateVlanInterface(t, master, parent, "30") 128 129 netName := "di-subinterface" 130 net.CreateNoError(t, context.Background(), client, netName, 131 net.WithIPvlan(parent, ""), 132 ) 133 assert.Check(t, n.IsNetworkAvailable(client, netName)) 134 135 _, err := net.Create(context.Background(), client, netName, 136 net.WithIPvlan(parent, ""), 137 ) 138 // verify that the overlap returns an error 139 assert.Check(t, err != nil) 140 } 141 } 142 143 func testIpvlanL2NilParent(client dclient.APIClient) func(*testing.T) { 144 return func(t *testing.T) { 145 // ipvlan l2 mode - dummy parent interface is provisioned dynamically 146 netName := "di-nil-parent" 147 net.CreateNoError(t, context.Background(), client, netName, 148 net.WithIPvlan("", ""), 149 ) 150 assert.Check(t, n.IsNetworkAvailable(client, netName)) 151 152 ctx := context.Background() 153 id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName)) 154 id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName)) 155 156 _, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 157 assert.NilError(t, err) 158 } 159 } 160 161 func testIpvlanL2InternalMode(client dclient.APIClient) func(*testing.T) { 162 return func(t *testing.T) { 163 netName := "di-internal" 164 net.CreateNoError(t, context.Background(), client, netName, 165 net.WithIPvlan("", ""), 166 net.WithInternal(), 167 ) 168 assert.Check(t, n.IsNetworkAvailable(client, netName)) 169 170 ctx := context.Background() 171 id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName)) 172 id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName)) 173 174 timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 175 defer cancel() 176 _, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"}) 177 // FIXME(vdemeester) check the time of error ? 178 assert.Check(t, err != nil) 179 assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded) 180 181 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 182 assert.NilError(t, err) 183 } 184 } 185 186 func testIpvlanL3NilParent(client dclient.APIClient) func(*testing.T) { 187 return func(t *testing.T) { 188 netName := "di-nil-parent-l3" 189 net.CreateNoError(t, context.Background(), client, netName, 190 net.WithIPvlan("", "l3"), 191 net.WithIPAM("172.28.230.0/24", ""), 192 net.WithIPAM("172.28.220.0/24", ""), 193 ) 194 assert.Check(t, n.IsNetworkAvailable(client, netName)) 195 196 ctx := context.Background() 197 id1 := container.Run(t, ctx, client, 198 container.WithNetworkMode(netName), 199 container.WithIPv4(netName, "172.28.220.10"), 200 ) 201 id2 := container.Run(t, ctx, client, 202 container.WithNetworkMode(netName), 203 container.WithIPv4(netName, "172.28.230.10"), 204 ) 205 206 _, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 207 assert.NilError(t, err) 208 } 209 } 210 211 func testIpvlanL3InternalMode(client dclient.APIClient) func(*testing.T) { 212 return func(t *testing.T) { 213 netName := "di-internal-l3" 214 net.CreateNoError(t, context.Background(), client, netName, 215 net.WithIPvlan("", "l3"), 216 net.WithInternal(), 217 net.WithIPAM("172.28.230.0/24", ""), 218 net.WithIPAM("172.28.220.0/24", ""), 219 ) 220 assert.Check(t, n.IsNetworkAvailable(client, netName)) 221 222 ctx := context.Background() 223 id1 := container.Run(t, ctx, client, 224 container.WithNetworkMode(netName), 225 container.WithIPv4(netName, "172.28.220.10"), 226 ) 227 id2 := container.Run(t, ctx, client, 228 container.WithNetworkMode(netName), 229 container.WithIPv4(netName, "172.28.230.10"), 230 ) 231 232 timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 233 defer cancel() 234 _, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"}) 235 // FIXME(vdemeester) check the time of error ? 236 assert.Check(t, err != nil) 237 assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded) 238 239 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 240 assert.NilError(t, err) 241 } 242 } 243 244 func testIpvlanL2MultiSubnet(client dclient.APIClient) func(*testing.T) { 245 return func(t *testing.T) { 246 netName := "dualstackl2" 247 net.CreateNoError(t, context.Background(), client, netName, 248 net.WithIPvlan("", ""), 249 net.WithIPv6(), 250 net.WithIPAM("172.28.200.0/24", ""), 251 net.WithIPAM("172.28.202.0/24", "172.28.202.254"), 252 net.WithIPAM("2001:db8:abc8::/64", ""), 253 net.WithIPAM("2001:db8:abc6::/64", "2001:db8:abc6::254"), 254 ) 255 assert.Check(t, n.IsNetworkAvailable(client, netName)) 256 257 // 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 258 ctx := context.Background() 259 id1 := container.Run(t, ctx, client, 260 container.WithNetworkMode(netName), 261 container.WithIPv4(netName, "172.28.200.20"), 262 container.WithIPv6(netName, "2001:db8:abc8::20"), 263 ) 264 id2 := container.Run(t, ctx, client, 265 container.WithNetworkMode(netName), 266 container.WithIPv4(netName, "172.28.200.21"), 267 container.WithIPv6(netName, "2001:db8:abc8::21"), 268 ) 269 c1, err := client.ContainerInspect(ctx, id1) 270 assert.NilError(t, err) 271 272 // verify ipv4 connectivity to the explicit --ipv address second to first 273 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks[netName].IPAddress}) 274 assert.NilError(t, err) 275 // verify ipv6 connectivity to the explicit --ipv6 address second to first 276 _, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks[netName].GlobalIPv6Address}) 277 assert.NilError(t, err) 278 279 // 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 280 id3 := container.Run(t, ctx, client, 281 container.WithNetworkMode(netName), 282 container.WithIPv4(netName, "172.28.202.20"), 283 container.WithIPv6(netName, "2001:db8:abc6::20"), 284 ) 285 id4 := container.Run(t, ctx, client, 286 container.WithNetworkMode(netName), 287 container.WithIPv4(netName, "172.28.202.21"), 288 container.WithIPv6(netName, "2001:db8:abc6::21"), 289 ) 290 c3, err := client.ContainerInspect(ctx, id3) 291 assert.NilError(t, err) 292 293 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 294 _, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks[netName].IPAddress}) 295 assert.NilError(t, err) 296 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 297 _, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks[netName].GlobalIPv6Address}) 298 assert.NilError(t, err) 299 300 // Inspect the v4 gateway to ensure the proper default GW was assigned 301 assert.Equal(t, c1.NetworkSettings.Networks[netName].Gateway, "172.28.200.1") 302 // Inspect the v6 gateway to ensure the proper default GW was assigned 303 assert.Equal(t, c1.NetworkSettings.Networks[netName].IPv6Gateway, "2001:db8:abc8::1") 304 // Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned 305 assert.Equal(t, c3.NetworkSettings.Networks[netName].Gateway, "172.28.202.254") 306 // Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned 307 assert.Equal(t, c3.NetworkSettings.Networks[netName].IPv6Gateway, "2001:db8:abc6::254") 308 } 309 } 310 311 func testIpvlanL3MultiSubnet(client dclient.APIClient) func(*testing.T) { 312 return func(t *testing.T) { 313 netName := "dualstackl3" 314 net.CreateNoError(t, context.Background(), client, netName, 315 net.WithIPvlan("", "l3"), 316 net.WithIPv6(), 317 net.WithIPAM("172.28.10.0/24", ""), 318 net.WithIPAM("172.28.12.0/24", "172.28.12.254"), 319 net.WithIPAM("2001:db8:abc9::/64", ""), 320 net.WithIPAM("2001:db8:abc7::/64", "2001:db8:abc7::254"), 321 ) 322 assert.Check(t, n.IsNetworkAvailable(client, netName)) 323 324 // 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 325 ctx := context.Background() 326 id1 := container.Run(t, ctx, client, 327 container.WithNetworkMode(netName), 328 container.WithIPv4(netName, "172.28.10.20"), 329 container.WithIPv6(netName, "2001:db8:abc9::20"), 330 ) 331 id2 := container.Run(t, ctx, client, 332 container.WithNetworkMode(netName), 333 container.WithIPv4(netName, "172.28.10.21"), 334 container.WithIPv6(netName, "2001:db8:abc9::21"), 335 ) 336 c1, err := client.ContainerInspect(ctx, id1) 337 assert.NilError(t, err) 338 339 // verify ipv4 connectivity to the explicit --ipv address second to first 340 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks[netName].IPAddress}) 341 assert.NilError(t, err) 342 // verify ipv6 connectivity to the explicit --ipv6 address second to first 343 _, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks[netName].GlobalIPv6Address}) 344 assert.NilError(t, err) 345 346 // 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 347 id3 := container.Run(t, ctx, client, 348 container.WithNetworkMode(netName), 349 container.WithIPv4(netName, "172.28.12.20"), 350 container.WithIPv6(netName, "2001:db8:abc7::20"), 351 ) 352 id4 := container.Run(t, ctx, client, 353 container.WithNetworkMode(netName), 354 container.WithIPv4(netName, "172.28.12.21"), 355 container.WithIPv6(netName, "2001:db8:abc7::21"), 356 ) 357 c3, err := client.ContainerInspect(ctx, id3) 358 assert.NilError(t, err) 359 360 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 361 _, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks[netName].IPAddress}) 362 assert.NilError(t, err) 363 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 364 _, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks[netName].GlobalIPv6Address}) 365 assert.NilError(t, err) 366 367 // Inspect the v4 gateway to ensure no next hop is assigned in L3 mode 368 assert.Equal(t, c1.NetworkSettings.Networks[netName].Gateway, "") 369 // Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled 370 assert.Equal(t, c1.NetworkSettings.Networks[netName].IPv6Gateway, "") 371 // Inspect the v4 gateway to ensure no next hop is assigned in L3 mode 372 assert.Equal(t, c3.NetworkSettings.Networks[netName].Gateway, "") 373 // Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled 374 assert.Equal(t, c3.NetworkSettings.Networks[netName].IPv6Gateway, "") 375 } 376 } 377 378 func testIpvlanAddressing(client dclient.APIClient) func(*testing.T) { 379 return func(t *testing.T) { 380 // Verify ipvlan l2 mode sets the proper default gateway routes via netlink 381 // for either an explicitly set route by the user or inferred via default IPAM 382 netNameL2 := "dualstackl2" 383 net.CreateNoError(t, context.Background(), client, netNameL2, 384 net.WithIPvlan("", "l2"), 385 net.WithIPv6(), 386 net.WithIPAM("172.28.140.0/24", "172.28.140.254"), 387 net.WithIPAM("2001:db8:abcb::/64", ""), 388 ) 389 assert.Check(t, n.IsNetworkAvailable(client, netNameL2)) 390 391 ctx := context.Background() 392 id1 := container.Run(t, ctx, client, 393 container.WithNetworkMode(netNameL2), 394 ) 395 // Validate ipvlan l2 mode defaults gateway sets the default IPAM next-hop inferred from the subnet 396 result, err := container.Exec(ctx, client, id1, []string{"ip", "route"}) 397 assert.NilError(t, err) 398 assert.Check(t, strings.Contains(result.Combined(), "default via 172.28.140.254 dev eth0")) 399 // Validate ipvlan l2 mode sets the v6 gateway to the user specified default gateway/next-hop 400 result, err = container.Exec(ctx, client, id1, []string{"ip", "-6", "route"}) 401 assert.NilError(t, err) 402 assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abcb::1 dev eth0")) 403 404 // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops 405 netNameL3 := "dualstackl3" 406 net.CreateNoError(t, context.Background(), client, netNameL3, 407 net.WithIPvlan("", "l3"), 408 net.WithIPv6(), 409 net.WithIPAM("172.28.160.0/24", "172.28.160.254"), 410 net.WithIPAM("2001:db8:abcd::/64", "2001:db8:abcd::254"), 411 ) 412 assert.Check(t, n.IsNetworkAvailable(client, netNameL3)) 413 414 id2 := container.Run(t, ctx, client, 415 container.WithNetworkMode(netNameL3), 416 ) 417 // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops 418 result, err = container.Exec(ctx, client, id2, []string{"ip", "route"}) 419 assert.NilError(t, err) 420 assert.Check(t, strings.Contains(result.Combined(), "default dev eth0")) 421 // Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops 422 result, err = container.Exec(ctx, client, id2, []string{"ip", "-6", "route"}) 423 assert.NilError(t, err) 424 assert.Check(t, strings.Contains(result.Combined(), "default dev eth0")) 425 } 426 } 427 428 // ensure Kernel version is >= v4.2 for ipvlan support 429 func ipvlanKernelSupport() bool { 430 return n.CheckKernelMajorVersionGreaterOrEqualThen(4, 2) 431 }