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