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