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.
16 // loopbackInterface returns an available logical network interface
17 // for loopback tests. It returns nil if no suitable interface is
19 func loopbackInterface() *Interface
{
20 ift
, err
:= Interfaces()
24 for _
, ifi
:= range ift
{
25 if ifi
.Flags
&FlagLoopback
!= 0 && ifi
.Flags
&FlagUp
!= 0 {
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 {
39 ifat
, err
:= ifi
.Addrs()
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()
53 func TestInterfaces(t
*testing
.T
) {
54 ift
, err
:= Interfaces()
58 for _
, ifi
:= range ift
{
59 ifxi
, err
:= InterfaceByIndex(ifi
.Index
)
64 case "solaris", "illumos":
65 if ifxi
.Index
!= ifi
.Index
{
66 t
.Errorf("got %v; want %v", ifxi
, ifi
)
69 if !reflect
.DeepEqual(ifxi
, &ifi
) {
70 t
.Errorf("got %v; want %v", ifxi
, ifi
)
73 ifxn
, err
:= InterfaceByName(ifi
.Name
)
77 if !reflect
.DeepEqual(ifxn
, &ifi
) {
78 t
.Errorf("got %v; want %v", ifxn
, ifi
)
80 t
.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi
.Name
, ifi
.Flags
, ifi
.Index
, ifi
.MTU
, ifi
.HardwareAddr
)
84 func TestInterfaceAddrs(t
*testing
.T
) {
85 ift
, err
:= Interfaces()
89 ifStats
:= interfaceStats(ift
)
90 ifat
, err
:= InterfaceAddrs()
94 uniStats
, err
:= validateInterfaceUnicastAddrs(ifat
)
98 if err
:= checkUnicastStats(ifStats
, uniStats
); err
!= nil {
103 func TestInterfaceUnicastAddrs(t
*testing
.T
) {
104 ift
, err
:= Interfaces()
108 ifStats
:= interfaceStats(ift
)
112 var uniStats routeStats
113 for _
, ifi
:= range ift
{
114 ifat
, err
:= ifi
.Addrs()
118 stats
, err
:= validateInterfaceUnicastAddrs(ifat
)
122 uniStats
.ipv4
+= stats
.ipv4
123 uniStats
.ipv6
+= stats
.ipv6
125 if err
:= checkUnicastStats(ifStats
, &uniStats
); err
!= nil {
130 func TestInterfaceMulticastAddrs(t
*testing
.T
) {
131 ift
, err
:= Interfaces()
135 ifStats
:= interfaceStats(ift
)
136 ifat
, err
:= InterfaceAddrs()
140 uniStats
, err
:= validateInterfaceUnicastAddrs(ifat
)
144 var multiStats routeStats
145 for _
, ifi
:= range ift
{
146 ifmat
, err
:= ifi
.MulticastAddrs()
150 stats
, err
:= validateInterfaceMulticastAddrs(ifmat
)
154 multiStats
.ipv4
+= stats
.ipv4
155 multiStats
.ipv6
+= stats
.ipv6
157 if err
:= checkMulticastStats(ifStats
, uniStats
, &multiStats
); err
!= nil {
162 type ifStats
struct {
163 loop
int // # of active loopback interfaces
164 other
int // # of active other interfaces
167 func interfaceStats(ift
[]Interface
) *ifStats
{
169 for _
, ifi
:= range ift
{
170 if ifi
.Flags
&FlagUp
!= 0 {
171 if ifi
.Flags
&FlagLoopback
!= 0 {
181 type routeStats
struct {
182 ipv4
, ipv6
int // # of active connected unicast, anycast or multicast routes
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) {
196 if ifa
== nil || ifa
.IP
== nil || ifa
.IP
.IsMulticast() || ifa
.Mask
== nil {
197 return nil, fmt
.Errorf("unexpected value: %#v", ifa
)
199 if len(ifa
.IP
) != IPv6len
{
200 return nil, fmt
.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa
)
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
)
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
)
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
)
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
)
222 if ifa
== nil || ifa
.IP
== nil || ifa
.IP
.IsMulticast() {
223 return nil, fmt
.Errorf("unexpected value: %#v", ifa
)
225 if len(ifa
.IP
) != IPv6len
{
226 return nil, fmt
.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa
)
228 if ifa
.IP
.To4() != nil {
231 if ifa
.IP
.To16() != nil && ifa
.IP
.To4() == nil {
235 return nil, fmt
.Errorf("unexpected type: %T", ifa
)
241 func validateInterfaceMulticastAddrs(ifat
[]Addr
) (*routeStats
, error
) {
242 stats
:= new(routeStats
)
243 for _
, ifa
:= range ifat
{
244 switch ifa
:= ifa
.(type) {
246 if ifa
== nil || ifa
.IP
== nil || ifa
.IP
.IsUnspecified() ||
!ifa
.IP
.IsMulticast() {
247 return nil, fmt
.Errorf("unexpected value: %#v", ifa
)
249 if len(ifa
.IP
) != IPv6len
{
250 return nil, fmt
.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa
)
252 if ifa
.IP
.To4() != nil {
255 if ifa
.IP
.To16() != nil && ifa
.IP
.To4() == nil {
259 return nil, fmt
.Errorf("unexpected type: %T", ifa
)
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
)
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
)
279 func checkMulticastStats(ifStats
*ifStats
, uniStats
, multiStats
*routeStats
) error
{
280 switch runtime
.GOOS
{
281 case "aix", "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "illumos":
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
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
)
302 func BenchmarkInterfaces(b
*testing
.B
) {
303 testHookUninstaller
.Do(uninstallTestHooks
)
305 for i
:= 0; i
< b
.N
; i
++ {
306 if _
, err
:= Interfaces(); err
!= nil {
312 func BenchmarkInterfaceByIndex(b
*testing
.B
) {
313 testHookUninstaller
.Do(uninstallTestHooks
)
315 ifi
:= loopbackInterface()
317 b
.Skip("loopback interface not found")
319 for i
:= 0; i
< b
.N
; i
++ {
320 if _
, err
:= InterfaceByIndex(ifi
.Index
); err
!= nil {
326 func BenchmarkInterfaceByName(b
*testing
.B
) {
327 testHookUninstaller
.Do(uninstallTestHooks
)
329 ifi
:= loopbackInterface()
331 b
.Skip("loopback interface not found")
333 for i
:= 0; i
< b
.N
; i
++ {
334 if _
, err
:= InterfaceByName(ifi
.Name
); err
!= nil {
340 func BenchmarkInterfaceAddrs(b
*testing
.B
) {
341 testHookUninstaller
.Do(uninstallTestHooks
)
343 for i
:= 0; i
< b
.N
; i
++ {
344 if _
, err
:= InterfaceAddrs(); err
!= nil {
350 func BenchmarkInterfacesAndAddrs(b
*testing
.B
) {
351 testHookUninstaller
.Do(uninstallTestHooks
)
353 ifi
:= loopbackInterface()
355 b
.Skip("loopback interface not found")
357 for i
:= 0; i
< b
.N
; i
++ {
358 if _
, err
:= ifi
.Addrs(); err
!= nil {
364 func BenchmarkInterfacesAndMulticastAddrs(b
*testing
.B
) {
365 testHookUninstaller
.Do(uninstallTestHooks
)
367 ifi
:= loopbackInterface()
369 b
.Skip("loopback interface not found")
371 for i
:= 0; i
< b
.N
; i
++ {
372 if _
, err
:= ifi
.MulticastAddrs(); err
!= nil {