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