fb6032fbc069a9f921c8aa344ddf927d823de564
[platform/upstream/gcc.git] / libgo / go / net / interface_test.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build !js
6
7 package net
8
9 import (
10         "fmt"
11         "reflect"
12         "runtime"
13         "testing"
14 )
15
16 // loopbackInterface returns an available logical network interface
17 // for loopback tests. It returns nil if no suitable interface is
18 // found.
19 func loopbackInterface() *Interface {
20         ift, err := Interfaces()
21         if err != nil {
22                 return nil
23         }
24         for _, ifi := range ift {
25                 if ifi.Flags&FlagLoopback != 0 && ifi.Flags&FlagUp != 0 {
26                         return &ifi
27                 }
28         }
29         return nil
30 }
31
32 // ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address
33 // on the given network interface for tests. It returns "" if no
34 // suitable address is found.
35 func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
36         if ifi == nil {
37                 return ""
38         }
39         ifat, err := ifi.Addrs()
40         if err != nil {
41                 return ""
42         }
43         for _, ifa := range ifat {
44                 if ifa, ok := ifa.(*IPNet); ok {
45                         if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
46                                 return ifa.IP.String()
47                         }
48                 }
49         }
50         return ""
51 }
52
53 func TestInterfaces(t *testing.T) {
54         ift, err := Interfaces()
55         if err != nil {
56                 t.Fatal(err)
57         }
58         for _, ifi := range ift {
59                 ifxi, err := InterfaceByIndex(ifi.Index)
60                 if err != nil {
61                         t.Fatal(err)
62                 }
63                 switch runtime.GOOS {
64                 case "solaris", "illumos":
65                         if ifxi.Index != ifi.Index {
66                                 t.Errorf("got %v; want %v", ifxi, ifi)
67                         }
68                 default:
69                         if !reflect.DeepEqual(ifxi, &ifi) {
70                                 t.Errorf("got %v; want %v", ifxi, ifi)
71                         }
72                 }
73                 ifxn, err := InterfaceByName(ifi.Name)
74                 if err != nil {
75                         t.Fatal(err)
76                 }
77                 if !reflect.DeepEqual(ifxn, &ifi) {
78                         t.Errorf("got %v; want %v", ifxn, ifi)
79                 }
80                 t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr)
81         }
82 }
83
84 func TestInterfaceAddrs(t *testing.T) {
85         ift, err := Interfaces()
86         if err != nil {
87                 t.Fatal(err)
88         }
89         ifStats := interfaceStats(ift)
90         ifat, err := InterfaceAddrs()
91         if err != nil {
92                 t.Fatal(err)
93         }
94         uniStats, err := validateInterfaceUnicastAddrs(ifat)
95         if err != nil {
96                 t.Fatal(err)
97         }
98         if err := checkUnicastStats(ifStats, uniStats); err != nil {
99                 t.Fatal(err)
100         }
101 }
102
103 func TestInterfaceUnicastAddrs(t *testing.T) {
104         ift, err := Interfaces()
105         if err != nil {
106                 t.Fatal(err)
107         }
108         ifStats := interfaceStats(ift)
109         if err != nil {
110                 t.Fatal(err)
111         }
112         var uniStats routeStats
113         for _, ifi := range ift {
114                 ifat, err := ifi.Addrs()
115                 if err != nil {
116                         t.Fatal(ifi, err)
117                 }
118                 stats, err := validateInterfaceUnicastAddrs(ifat)
119                 if err != nil {
120                         t.Fatal(ifi, err)
121                 }
122                 uniStats.ipv4 += stats.ipv4
123                 uniStats.ipv6 += stats.ipv6
124         }
125         if err := checkUnicastStats(ifStats, &uniStats); err != nil {
126                 t.Fatal(err)
127         }
128 }
129
130 func TestInterfaceMulticastAddrs(t *testing.T) {
131         ift, err := Interfaces()
132         if err != nil {
133                 t.Fatal(err)
134         }
135         ifStats := interfaceStats(ift)
136         ifat, err := InterfaceAddrs()
137         if err != nil {
138                 t.Fatal(err)
139         }
140         uniStats, err := validateInterfaceUnicastAddrs(ifat)
141         if err != nil {
142                 t.Fatal(err)
143         }
144         var multiStats routeStats
145         for _, ifi := range ift {
146                 ifmat, err := ifi.MulticastAddrs()
147                 if err != nil {
148                         t.Fatal(ifi, err)
149                 }
150                 stats, err := validateInterfaceMulticastAddrs(ifmat)
151                 if err != nil {
152                         t.Fatal(ifi, err)
153                 }
154                 multiStats.ipv4 += stats.ipv4
155                 multiStats.ipv6 += stats.ipv6
156         }
157         if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil {
158                 t.Fatal(err)
159         }
160 }
161
162 type ifStats struct {
163         loop  int // # of active loopback interfaces
164         other int // # of active other interfaces
165 }
166
167 func interfaceStats(ift []Interface) *ifStats {
168         var stats ifStats
169         for _, ifi := range ift {
170                 if ifi.Flags&FlagUp != 0 {
171                         if ifi.Flags&FlagLoopback != 0 {
172                                 stats.loop++
173                         } else {
174                                 stats.other++
175                         }
176                 }
177         }
178         return &stats
179 }
180
181 type routeStats struct {
182         ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes
183 }
184
185 func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) {
186         // Note: BSD variants allow assigning any IPv4/IPv6 address
187         // prefix to IP interface. For example,
188         //   - 0.0.0.0/0 through 255.255.255.255/32
189         //   - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128
190         // In other words, there is no tightly-coupled combination of
191         // interface address prefixes and connected routes.
192         stats := new(routeStats)
193         for _, ifa := range ifat {
194                 switch ifa := ifa.(type) {
195                 case *IPNet:
196                         if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil {
197                                 return nil, fmt.Errorf("unexpected value: %#v", ifa)
198                         }
199                         if len(ifa.IP) != IPv6len {
200                                 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
201                         }
202                         prefixLen, maxPrefixLen := ifa.Mask.Size()
203                         if ifa.IP.To4() != nil {
204                                 if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
205                                         return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
206                                 }
207                                 if ifa.IP.IsLoopback() && prefixLen < 8 { // see RFC 1122
208                                         return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
209                                 }
210                                 stats.ipv4++
211                         }
212                         if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
213                                 if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
214                                         return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
215                                 }
216                                 if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
217                                         return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
218                                 }
219                                 stats.ipv6++
220                         }
221                 case *IPAddr:
222                         if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() {
223                                 return nil, fmt.Errorf("unexpected value: %#v", ifa)
224                         }
225                         if len(ifa.IP) != IPv6len {
226                                 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
227                         }
228                         if ifa.IP.To4() != nil {
229                                 stats.ipv4++
230                         }
231                         if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
232                                 stats.ipv6++
233                         }
234                 default:
235                         return nil, fmt.Errorf("unexpected type: %T", ifa)
236                 }
237         }
238         return stats, nil
239 }
240
241 func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
242         stats := new(routeStats)
243         for _, ifa := range ifat {
244                 switch ifa := ifa.(type) {
245                 case *IPAddr:
246                         if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() {
247                                 return nil, fmt.Errorf("unexpected value: %#v", ifa)
248                         }
249                         if len(ifa.IP) != IPv6len {
250                                 return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
251                         }
252                         if ifa.IP.To4() != nil {
253                                 stats.ipv4++
254                         }
255                         if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
256                                 stats.ipv6++
257                         }
258                 default:
259                         return nil, fmt.Errorf("unexpected type: %T", ifa)
260                 }
261         }
262         return stats, nil
263 }
264
265 func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error {
266         // Test the existence of connected unicast routes for IPv4.
267         if supportsIPv4() && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 {
268                 return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
269         }
270         // Test the existence of connected unicast routes for IPv6.
271         // We can assume the existence of ::1/128 when at least one
272         // loopback interface is installed.
273         if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 == 0 {
274                 return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
275         }
276         return nil
277 }
278
279 func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error {
280         switch runtime.GOOS {
281         case "aix", "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris", "illumos":
282         default:
283                 // Test the existence of connected multicast route
284                 // clones for IPv4. Unlike IPv6, IPv4 multicast
285                 // capability is not a mandatory feature, and so IPv4
286                 // multicast validation is ignored and we only check
287                 // IPv6 below.
288                 //
289                 // Test the existence of connected multicast route
290                 // clones for IPv6. Some platform never uses loopback
291                 // interface as the nexthop for multicast routing.
292                 // We can assume the existence of connected multicast
293                 // route clones when at least two connected unicast
294                 // routes, ::1/128 and other, are installed.
295                 if supportsIPv6() && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 {
296                         return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats)
297                 }
298         }
299         return nil
300 }
301
302 func BenchmarkInterfaces(b *testing.B) {
303         testHookUninstaller.Do(uninstallTestHooks)
304
305         for i := 0; i < b.N; i++ {
306                 if _, err := Interfaces(); err != nil {
307                         b.Fatal(err)
308                 }
309         }
310 }
311
312 func BenchmarkInterfaceByIndex(b *testing.B) {
313         testHookUninstaller.Do(uninstallTestHooks)
314
315         ifi := loopbackInterface()
316         if ifi == nil {
317                 b.Skip("loopback interface not found")
318         }
319         for i := 0; i < b.N; i++ {
320                 if _, err := InterfaceByIndex(ifi.Index); err != nil {
321                         b.Fatal(err)
322                 }
323         }
324 }
325
326 func BenchmarkInterfaceByName(b *testing.B) {
327         testHookUninstaller.Do(uninstallTestHooks)
328
329         ifi := loopbackInterface()
330         if ifi == nil {
331                 b.Skip("loopback interface not found")
332         }
333         for i := 0; i < b.N; i++ {
334                 if _, err := InterfaceByName(ifi.Name); err != nil {
335                         b.Fatal(err)
336                 }
337         }
338 }
339
340 func BenchmarkInterfaceAddrs(b *testing.B) {
341         testHookUninstaller.Do(uninstallTestHooks)
342
343         for i := 0; i < b.N; i++ {
344                 if _, err := InterfaceAddrs(); err != nil {
345                         b.Fatal(err)
346                 }
347         }
348 }
349
350 func BenchmarkInterfacesAndAddrs(b *testing.B) {
351         testHookUninstaller.Do(uninstallTestHooks)
352
353         ifi := loopbackInterface()
354         if ifi == nil {
355                 b.Skip("loopback interface not found")
356         }
357         for i := 0; i < b.N; i++ {
358                 if _, err := ifi.Addrs(); err != nil {
359                         b.Fatal(err)
360                 }
361         }
362 }
363
364 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
365         testHookUninstaller.Do(uninstallTestHooks)
366
367         ifi := loopbackInterface()
368         if ifi == nil {
369                 b.Skip("loopback interface not found")
370         }
371         for i := 0; i < b.N; i++ {
372                 if _, err := ifi.MulticastAddrs(); err != nil {
373                         b.Fatal(err)
374                 }
375         }
376 }