github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration/network/macvlan/macvlan_test.go (about) 1 package macvlan 2 3 import ( 4 "context" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/network" 11 "github.com/docker/docker/client" 12 "github.com/docker/docker/integration/internal/container" 13 n "github.com/docker/docker/integration/network" 14 "github.com/docker/docker/internal/test/daemon" 15 "github.com/gotestyourself/gotestyourself/assert" 16 "github.com/gotestyourself/gotestyourself/skip" 17 ) 18 19 func TestDockerNetworkMacvlanPersistance(t *testing.T) { 20 // verify the driver automatically provisions the 802.1q link (dm-dummy0.60) 21 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 22 skip.If(t, testEnv.IsRemoteDaemon()) 23 skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan") 24 25 d := daemon.New(t) 26 d.StartWithBusybox(t) 27 defer d.Stop(t) 28 29 master := "dm-dummy0" 30 n.CreateMasterDummy(t, master) 31 defer n.DeleteInterface(t, master) 32 33 client, err := d.NewClient() 34 assert.NilError(t, err) 35 36 _, err = client.NetworkCreate(context.Background(), "dm-persist", types.NetworkCreate{ 37 Driver: "macvlan", 38 Options: map[string]string{ 39 "parent": "dm-dummy0.60", 40 }, 41 }) 42 assert.NilError(t, err) 43 assert.Check(t, n.IsNetworkAvailable(client, "dm-persist")) 44 d.Restart(t) 45 assert.Check(t, n.IsNetworkAvailable(client, "dm-persist")) 46 } 47 48 func TestDockerNetworkMacvlan(t *testing.T) { 49 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 50 skip.If(t, testEnv.IsRemoteDaemon()) 51 skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan") 52 53 for _, tc := range []struct { 54 name string 55 test func(client.APIClient) func(*testing.T) 56 }{ 57 { 58 name: "Subinterface", 59 test: testMacvlanSubinterface, 60 }, { 61 name: "OverlapParent", 62 test: testMacvlanOverlapParent, 63 }, { 64 name: "NilParent", 65 test: testMacvlanNilParent, 66 }, { 67 name: "InternalMode", 68 test: testMacvlanInternalMode, 69 }, { 70 name: "Addressing", 71 test: testMacvlanAddressing, 72 }, 73 } { 74 d := daemon.New(t) 75 d.StartWithBusybox(t) 76 77 client, err := d.NewClient() 78 assert.NilError(t, err) 79 80 t.Run(tc.name, tc.test(client)) 81 82 d.Stop(t) 83 // FIXME(vdemeester) clean network 84 } 85 } 86 87 func testMacvlanOverlapParent(client client.APIClient) func(*testing.T) { 88 return func(t *testing.T) { 89 // verify the same parent interface cannot be used if already in use by an existing network 90 master := "dm-dummy0" 91 n.CreateMasterDummy(t, master) 92 defer n.DeleteInterface(t, master) 93 94 _, err := client.NetworkCreate(context.Background(), "dm-subinterface", types.NetworkCreate{ 95 Driver: "macvlan", 96 Options: map[string]string{ 97 "parent": "dm-dummy0.40", 98 }, 99 }) 100 assert.NilError(t, err) 101 assert.Check(t, n.IsNetworkAvailable(client, "dm-subinterface")) 102 103 _, err = client.NetworkCreate(context.Background(), "dm-parent-net-overlap", types.NetworkCreate{ 104 Driver: "macvlan", 105 Options: map[string]string{ 106 "parent": "dm-dummy0.40", 107 }, 108 }) 109 assert.Check(t, err != nil) 110 // delete the network while preserving the parent link 111 err = client.NetworkRemove(context.Background(), "dm-subinterface") 112 assert.NilError(t, err) 113 114 assert.Check(t, n.IsNetworkNotAvailable(client, "dm-subinterface")) 115 // verify the network delete did not delete the predefined link 116 n.LinkExists(t, "dm-dummy0") 117 } 118 } 119 120 func testMacvlanSubinterface(client client.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 := "dm-dummy0" 124 n.CreateMasterDummy(t, master) 125 defer n.DeleteInterface(t, master) 126 n.CreateVlanInterface(t, master, "dm-dummy0.20", "20") 127 128 _, err := client.NetworkCreate(context.Background(), "dm-subinterface", types.NetworkCreate{ 129 Driver: "macvlan", 130 Options: map[string]string{ 131 "parent": "dm-dummy0.20", 132 }, 133 }) 134 assert.NilError(t, err) 135 assert.Check(t, n.IsNetworkAvailable(client, "dm-subinterface")) 136 137 // delete the network while preserving the parent link 138 err = client.NetworkRemove(context.Background(), "dm-subinterface") 139 assert.NilError(t, err) 140 141 assert.Check(t, n.IsNetworkNotAvailable(client, "dm-subinterface")) 142 // verify the network delete did not delete the predefined link 143 n.LinkExists(t, "dm-dummy0.20") 144 } 145 } 146 147 func testMacvlanNilParent(client client.APIClient) func(*testing.T) { 148 return func(t *testing.T) { 149 // macvlan bridge mode - dummy parent interface is provisioned dynamically 150 _, err := client.NetworkCreate(context.Background(), "dm-nil-parent", types.NetworkCreate{ 151 Driver: "macvlan", 152 }) 153 assert.NilError(t, err) 154 assert.Check(t, n.IsNetworkAvailable(client, "dm-nil-parent")) 155 156 ctx := context.Background() 157 id1 := container.Run(t, ctx, client, container.WithNetworkMode("dm-nil-parent")) 158 id2 := container.Run(t, ctx, client, container.WithNetworkMode("dm-nil-parent")) 159 160 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 161 assert.Check(t, err == nil) 162 } 163 } 164 165 func testMacvlanInternalMode(client client.APIClient) func(*testing.T) { 166 return func(t *testing.T) { 167 // macvlan bridge mode - dummy parent interface is provisioned dynamically 168 _, err := client.NetworkCreate(context.Background(), "dm-internal", types.NetworkCreate{ 169 Driver: "macvlan", 170 Internal: true, 171 }) 172 assert.NilError(t, err) 173 assert.Check(t, n.IsNetworkAvailable(client, "dm-internal")) 174 175 ctx := context.Background() 176 id1 := container.Run(t, ctx, client, container.WithNetworkMode("dm-internal")) 177 id2 := container.Run(t, ctx, client, container.WithNetworkMode("dm-internal")) 178 179 timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 180 defer cancel() 181 _, err = container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"}) 182 // FIXME(vdemeester) check the time of error ? 183 assert.Check(t, err != nil) 184 assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded) 185 186 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 187 assert.Check(t, err == nil) 188 } 189 } 190 191 func testMacvlanMultiSubnet(client client.APIClient) func(*testing.T) { 192 return func(t *testing.T) { 193 _, err := client.NetworkCreate(context.Background(), "dualstackbridge", types.NetworkCreate{ 194 Driver: "macvlan", 195 EnableIPv6: true, 196 IPAM: &network.IPAM{ 197 Config: []network.IPAMConfig{ 198 { 199 Subnet: "172.28.100.0/24", 200 AuxAddress: map[string]string{}, 201 }, 202 { 203 Subnet: "172.28.102.0/24", 204 Gateway: "172.28.102.254", 205 AuxAddress: map[string]string{}, 206 }, 207 { 208 Subnet: "2001:db8:abc2::/64", 209 AuxAddress: map[string]string{}, 210 }, 211 { 212 Subnet: "2001:db8:abc4::/64", 213 Gateway: "2001:db8:abc4::254", 214 AuxAddress: map[string]string{}, 215 }, 216 }, 217 }, 218 }) 219 assert.NilError(t, err) 220 assert.Check(t, n.IsNetworkAvailable(client, "dualstackbridge")) 221 222 // 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 223 ctx := context.Background() 224 id1 := container.Run(t, ctx, client, 225 container.WithNetworkMode("dualstackbridge"), 226 container.WithIPv4("dualstackbridge", "172.28.100.20"), 227 container.WithIPv6("dualstackbridge", "2001:db8:abc2::20"), 228 ) 229 id2 := container.Run(t, ctx, client, 230 container.WithNetworkMode("dualstackbridge"), 231 container.WithIPv4("dualstackbridge", "172.28.100.21"), 232 container.WithIPv6("dualstackbridge", "2001:db8:abc2::21"), 233 ) 234 c1, err := client.ContainerInspect(ctx, id1) 235 assert.NilError(t, err) 236 237 // verify ipv4 connectivity to the explicit --ipv address second to first 238 _, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].IPAddress}) 239 assert.NilError(t, err) 240 // verify ipv6 connectivity to the explicit --ipv6 address second to first 241 _, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address}) 242 assert.NilError(t, err) 243 244 // 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 245 id3 := container.Run(t, ctx, client, 246 container.WithNetworkMode("dualstackbridge"), 247 container.WithIPv4("dualstackbridge", "172.28.102.20"), 248 container.WithIPv6("dualstackbridge", "2001:db8:abc4::20"), 249 ) 250 id4 := container.Run(t, ctx, client, 251 container.WithNetworkMode("dualstackbridge"), 252 container.WithIPv4("dualstackbridge", "172.28.102.21"), 253 container.WithIPv6("dualstackbridge", "2001:db8:abc4::21"), 254 ) 255 c3, err := client.ContainerInspect(ctx, id3) 256 assert.NilError(t, err) 257 258 // verify ipv4 connectivity to the explicit --ipv address from third to fourth 259 _, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].IPAddress}) 260 assert.NilError(t, err) 261 // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth 262 _, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address}) 263 assert.NilError(t, err) 264 265 // Inspect the v4 gateway to ensure the proper default GW was assigned 266 assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.100.1") 267 // Inspect the v6 gateway to ensure the proper default GW was assigned 268 assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8:abc2::1") 269 // Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned 270 assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.102.254") 271 // Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned 272 assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8.abc4::254") 273 } 274 } 275 276 func testMacvlanAddressing(client client.APIClient) func(*testing.T) { 277 return func(t *testing.T) { 278 // Ensure the default gateways, next-hops and default dev devices are properly set 279 _, err := client.NetworkCreate(context.Background(), "dualstackbridge", types.NetworkCreate{ 280 Driver: "macvlan", 281 EnableIPv6: true, 282 Options: map[string]string{ 283 "macvlan_mode": "bridge", 284 }, 285 IPAM: &network.IPAM{ 286 Config: []network.IPAMConfig{ 287 { 288 Subnet: "172.28.130.0/24", 289 AuxAddress: map[string]string{}, 290 }, 291 { 292 Subnet: "2001:db8:abca::/64", 293 Gateway: "2001:db8:abca::254", 294 AuxAddress: map[string]string{}, 295 }, 296 }, 297 }, 298 }) 299 assert.NilError(t, err) 300 assert.Check(t, n.IsNetworkAvailable(client, "dualstackbridge")) 301 302 ctx := context.Background() 303 id1 := container.Run(t, ctx, client, 304 container.WithNetworkMode("dualstackbridge"), 305 ) 306 307 // Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet 308 result, err := container.Exec(ctx, client, id1, []string{"ip", "route"}) 309 assert.NilError(t, err) 310 assert.Check(t, strings.Contains(result.Combined(), "default via 172.28.130.1 dev eth0")) 311 // Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop 312 result, err = container.Exec(ctx, client, id1, []string{"ip", "-6", "route"}) 313 assert.NilError(t, err) 314 assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abca::254 dev eth0")) 315 } 316 } 317 318 // ensure Kernel version is >= v3.9 for macvlan support 319 func macvlanKernelSupport() bool { 320 return n.CheckKernelMajorVersionGreaterOrEqualThen(3, 9) 321 }