github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/integration/network/macvlan/macvlan_test.go (about) 1 // +build !windows 2 3 package macvlan // import "github.com/demonoid81/moby/integration/network/macvlan" 4 5 import ( 6 "context" 7 "strings" 8 "testing" 9 10 "github.com/demonoid81/moby/client" 11 "github.com/demonoid81/moby/integration/internal/container" 12 net "github.com/demonoid81/moby/integration/internal/network" 13 n "github.com/demonoid81/moby/integration/network" 14 "github.com/demonoid81/moby/testutil/daemon" 15 "gotest.tools/v3/assert" 16 "gotest.tools/v3/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.IsRemoteDaemon) 22 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 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 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 46 47 for _, tc := range []struct { 48 name string 49 test func(client.APIClient) func(*testing.T) 50 }{ 51 { 52 name: "Subinterface", 53 test: testMacvlanSubinterface, 54 }, { 55 name: "OverlapParent", 56 test: testMacvlanOverlapParent, 57 }, { 58 name: "NilParent", 59 test: testMacvlanNilParent, 60 }, { 61 name: "InternalMode", 62 test: testMacvlanInternalMode, 63 }, { 64 name: "MultiSubnet", 65 test: testMacvlanMultiSubnet, 66 }, { 67 name: "Addressing", 68 test: testMacvlanAddressing, 69 }, 70 } { 71 d := daemon.New(t) 72 d.StartWithBusybox(t) 73 c := d.NewClientT(t) 74 75 t.Run(tc.name, tc.test(c)) 76 77 d.Stop(t) 78 // FIXME(vdemeester) clean network 79 } 80 } 81 82 func testMacvlanOverlapParent(client client.APIClient) func(*testing.T) { 83 return func(t *testing.T) { 84 // verify the same parent interface cannot be used if already in use by an existing network 85 master := "dm-dummy0" 86 n.CreateMasterDummy(t, master) 87 defer n.DeleteInterface(t, master) 88 89 netName := "dm-subinterface" 90 parentName := "dm-dummy0.40" 91 net.CreateNoError(context.Background(), t, client, netName, 92 net.WithMacvlan(parentName), 93 ) 94 assert.Check(t, n.IsNetworkAvailable(client, netName)) 95 96 _, err := net.Create(context.Background(), client, "dm-parent-net-overlap", 97 net.WithMacvlan(parentName), 98 ) 99 assert.Check(t, err != nil) 100 101 // delete the network while preserving the parent link 102 err = client.NetworkRemove(context.Background(), netName) 103 assert.NilError(t, err) 104 105 assert.Check(t, n.IsNetworkNotAvailable(client, netName)) 106 // verify the network delete did not delete the predefined link 107 n.LinkExists(t, master) 108 } 109 } 110 111 func testMacvlanSubinterface(client client.APIClient) func(*testing.T) { 112 return func(t *testing.T) { 113 // verify the same parent interface cannot be used if already in use by an existing network 114 master := "dm-dummy0" 115 parentName := "dm-dummy0.20" 116 n.CreateMasterDummy(t, master) 117 defer n.DeleteInterface(t, master) 118 n.CreateVlanInterface(t, master, parentName, "20") 119 120 netName := "dm-subinterface" 121 net.CreateNoError(context.Background(), t, client, netName, 122 net.WithMacvlan(parentName), 123 ) 124 assert.Check(t, n.IsNetworkAvailable(client, netName)) 125 126 // delete the network while preserving the parent link 127 err := client.NetworkRemove(context.Background(), netName) 128 assert.NilError(t, err) 129 130 assert.Check(t, n.IsNetworkNotAvailable(client, netName)) 131 // verify the network delete did not delete the predefined link 132 n.LinkExists(t, parentName) 133 } 134 } 135 136 func testMacvlanNilParent(client client.APIClient) func(*testing.T) { 137 return func(t *testing.T) { 138 // macvlan bridge mode - dummy parent interface is provisioned dynamically 139 netName := "dm-nil-parent" 140 net.CreateNoError(context.Background(), t, client, netName, 141 net.WithMacvlan(""), 142 ) 143 assert.Check(t, n.IsNetworkAvailable(client, netName)) 144 145 ctx := context.Background() 146 id1 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) 147 id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) 148 149 _, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) 150 assert.Check(t, err == nil) 151 } 152 } 153 154 func testMacvlanInternalMode(client client.APIClient) func(*testing.T) { 155 return func(t *testing.T) { 156 // macvlan bridge mode - dummy parent interface is provisioned dynamically 157 netName := "dm-internal" 158 net.CreateNoError(context.Background(), t, client, netName, 159 net.WithMacvlan(""), 160 net.WithInternal(), 161 ) 162 assert.Check(t, n.IsNetworkAvailable(client, netName)) 163 164 ctx := context.Background() 165 id1 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) 166 id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) 167 168 result, _ := container.Exec(ctx, client, id1, []string{"ping", "-c", "1", "8.8.8.8"}) 169 assert.Check(t, strings.Contains(result.Combined(), "Network is unreachable")) 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 }