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