Home | History | Annotate | Download | only in net
      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 package net
      6 
      7 import (
      8 	"reflect"
      9 	"runtime"
     10 	"testing"
     11 )
     12 
     13 // loopbackInterface returns an available logical network interface
     14 // for loopback tests.  It returns nil if no suitable interface is
     15 // found.
     16 func loopbackInterface() *Interface {
     17 	ift, err := Interfaces()
     18 	if err != nil {
     19 		return nil
     20 	}
     21 	for _, ifi := range ift {
     22 		if ifi.Flags&FlagLoopback != 0 && ifi.Flags&FlagUp != 0 {
     23 			return &ifi
     24 		}
     25 	}
     26 	return nil
     27 }
     28 
     29 // ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address
     30 // on the given network interface for tests. It returns "" if no
     31 // suitable address is found.
     32 func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
     33 	if ifi == nil {
     34 		return ""
     35 	}
     36 	ifat, err := ifi.Addrs()
     37 	if err != nil {
     38 		return ""
     39 	}
     40 	for _, ifa := range ifat {
     41 		if ifa, ok := ifa.(*IPNet); ok {
     42 			if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
     43 				return ifa.IP.String()
     44 			}
     45 		}
     46 	}
     47 	return ""
     48 }
     49 
     50 type routeStats struct {
     51 	loop  int // # of active loopback interfaces
     52 	other int // # of active other interfaces
     53 
     54 	uni4, uni6     int // # of active connected unicast, anycast routes
     55 	multi4, multi6 int // # of active connected multicast route clones
     56 }
     57 
     58 func TestInterfaces(t *testing.T) {
     59 	ift, err := Interfaces()
     60 	if err != nil {
     61 		t.Fatal(err)
     62 	}
     63 	var stats routeStats
     64 	for _, ifi := range ift {
     65 		ifxi, err := InterfaceByIndex(ifi.Index)
     66 		if err != nil {
     67 			t.Fatal(err)
     68 		}
     69 		if !reflect.DeepEqual(ifxi, &ifi) {
     70 			t.Errorf("got %v; want %v", ifxi, ifi)
     71 		}
     72 		ifxn, err := InterfaceByName(ifi.Name)
     73 		if err != nil {
     74 			t.Fatal(err)
     75 		}
     76 		if !reflect.DeepEqual(ifxn, &ifi) {
     77 			t.Errorf("got %v; want %v", ifxn, ifi)
     78 		}
     79 		t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
     80 		t.Logf("hardware address %q", ifi.HardwareAddr.String())
     81 		if ifi.Flags&FlagUp != 0 {
     82 			if ifi.Flags&FlagLoopback != 0 {
     83 				stats.loop++
     84 			} else {
     85 				stats.other++
     86 			}
     87 		}
     88 		n4, n6 := testInterfaceAddrs(t, &ifi)
     89 		stats.uni4 += n4
     90 		stats.uni6 += n6
     91 		n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
     92 		stats.multi4 += n4
     93 		stats.multi6 += n6
     94 	}
     95 	switch runtime.GOOS {
     96 	case "nacl", "plan9", "solaris":
     97 	default:
     98 		// Test the existence of connected unicast routes for
     99 		// IPv4.
    100 		if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
    101 			t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
    102 		}
    103 		// Test the existence of connected unicast routes for
    104 		// IPv6. We can assume the existence of ::1/128 when
    105 		// at least one looopback interface is installed.
    106 		if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
    107 			t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
    108 		}
    109 	}
    110 	switch runtime.GOOS {
    111 	case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
    112 	default:
    113 		// Test the existence of connected multicast route
    114 		// clones for IPv4. Unlike IPv6, IPv4 multicast
    115 		// capability is not a mandatory feature, and so this
    116 		// test is disabled.
    117 		//if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 {
    118 		//	t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats)
    119 		//}
    120 		// Test the existence of connected multicast route
    121 		// clones for IPv6. Some platform never uses loopback
    122 		// interface as the nexthop for multicast routing.
    123 		// We can assume the existence of connected multicast
    124 		// route clones when at least two connected unicast
    125 		// routes, ::1/128 and other, are installed.
    126 		if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 {
    127 			t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats)
    128 		}
    129 	}
    130 }
    131 
    132 func TestInterfaceAddrs(t *testing.T) {
    133 	ift, err := Interfaces()
    134 	if err != nil {
    135 		t.Fatal(err)
    136 	}
    137 	var stats routeStats
    138 	for _, ifi := range ift {
    139 		if ifi.Flags&FlagUp != 0 {
    140 			if ifi.Flags&FlagLoopback != 0 {
    141 				stats.loop++
    142 			} else {
    143 				stats.other++
    144 			}
    145 		}
    146 	}
    147 	ifat, err := InterfaceAddrs()
    148 	if err != nil {
    149 		t.Fatal(err)
    150 	}
    151 	stats.uni4, stats.uni6 = testAddrs(t, ifat)
    152 	// Test the existence of connected unicast routes for IPv4.
    153 	if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
    154 		t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
    155 	}
    156 	// Test the existence of connected unicast routes for IPv6.
    157 	// We can assume the existence of ::1/128 when at least one
    158 	// looopback interface is installed.
    159 	if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
    160 		t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
    161 	}
    162 }
    163 
    164 func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
    165 	ifat, err := ifi.Addrs()
    166 	if err != nil {
    167 		t.Fatal(err)
    168 	}
    169 	return testAddrs(t, ifat)
    170 }
    171 
    172 func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
    173 	ifmat, err := ifi.MulticastAddrs()
    174 	if err != nil {
    175 		t.Fatal(err)
    176 	}
    177 	return testMulticastAddrs(t, ifmat)
    178 }
    179 
    180 func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
    181 	for _, ifa := range ifat {
    182 		switch ifa := ifa.(type) {
    183 		case *IPNet:
    184 			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
    185 				t.Errorf("unexpected value: %#v", ifa)
    186 				continue
    187 			}
    188 			prefixLen, maxPrefixLen := ifa.Mask.Size()
    189 			if ifa.IP.To4() != nil {
    190 				if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
    191 					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
    192 					continue
    193 				}
    194 				naf4++
    195 			} else if ifa.IP.To16() != nil {
    196 				if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
    197 					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
    198 					continue
    199 				}
    200 				naf6++
    201 			}
    202 			t.Logf("interface address %q", ifa.String())
    203 		default:
    204 			t.Errorf("unexpected type: %T", ifa)
    205 		}
    206 	}
    207 	return
    208 }
    209 
    210 func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
    211 	for _, ifma := range ifmat {
    212 		switch ifma := ifma.(type) {
    213 		case *IPAddr:
    214 			if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
    215 				t.Errorf("unexpected value: %#v", ifma)
    216 				continue
    217 			}
    218 			if ifma.IP.To4() != nil {
    219 				nmaf4++
    220 			} else if ifma.IP.To16() != nil {
    221 				nmaf6++
    222 			}
    223 			t.Logf("joined group address %q", ifma.String())
    224 		default:
    225 			t.Errorf("unexpected type: %T", ifma)
    226 		}
    227 	}
    228 	return
    229 }
    230 
    231 func BenchmarkInterfaces(b *testing.B) {
    232 	testHookUninstaller.Do(uninstallTestHooks)
    233 
    234 	for i := 0; i < b.N; i++ {
    235 		if _, err := Interfaces(); err != nil {
    236 			b.Fatal(err)
    237 		}
    238 	}
    239 }
    240 
    241 func BenchmarkInterfaceByIndex(b *testing.B) {
    242 	testHookUninstaller.Do(uninstallTestHooks)
    243 
    244 	ifi := loopbackInterface()
    245 	if ifi == nil {
    246 		b.Skip("loopback interface not found")
    247 	}
    248 	for i := 0; i < b.N; i++ {
    249 		if _, err := InterfaceByIndex(ifi.Index); err != nil {
    250 			b.Fatal(err)
    251 		}
    252 	}
    253 }
    254 
    255 func BenchmarkInterfaceByName(b *testing.B) {
    256 	testHookUninstaller.Do(uninstallTestHooks)
    257 
    258 	ifi := loopbackInterface()
    259 	if ifi == nil {
    260 		b.Skip("loopback interface not found")
    261 	}
    262 	for i := 0; i < b.N; i++ {
    263 		if _, err := InterfaceByName(ifi.Name); err != nil {
    264 			b.Fatal(err)
    265 		}
    266 	}
    267 }
    268 
    269 func BenchmarkInterfaceAddrs(b *testing.B) {
    270 	testHookUninstaller.Do(uninstallTestHooks)
    271 
    272 	for i := 0; i < b.N; i++ {
    273 		if _, err := InterfaceAddrs(); err != nil {
    274 			b.Fatal(err)
    275 		}
    276 	}
    277 }
    278 
    279 func BenchmarkInterfacesAndAddrs(b *testing.B) {
    280 	testHookUninstaller.Do(uninstallTestHooks)
    281 
    282 	ifi := loopbackInterface()
    283 	if ifi == nil {
    284 		b.Skip("loopback interface not found")
    285 	}
    286 	for i := 0; i < b.N; i++ {
    287 		if _, err := ifi.Addrs(); err != nil {
    288 			b.Fatal(err)
    289 		}
    290 	}
    291 }
    292 
    293 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
    294 	testHookUninstaller.Do(uninstallTestHooks)
    295 
    296 	ifi := loopbackInterface()
    297 	if ifi == nil {
    298 		b.Skip("loopback interface not found")
    299 	}
    300 	for i := 0; i < b.N; i++ {
    301 		if _, err := ifi.MulticastAddrs(); err != nil {
    302 			b.Fatal(err)
    303 		}
    304 	}
    305 }
    306