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", "nacl", "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 {