1
0
mirror of https://github.com/golang/go synced 2024-11-26 16:07:00 -07:00

net: fix slow network interface manipulations

This CL reduces unnecessary network facility lookups introduced
by recent changes below.

changeset: 15798:53a4da6a4f4a
net: return correct point-to-point interface address on linux

changeset: 15799:a81ef8e0cc05
net: set up IPv6 scoped addressing zone for network facilities

Also adds a test case for issue	4839.

Benchmark results on linux/amd64, virtual machine:
benchmark                                 old ns/op    new ns/op    delta
BenchmarkInterfaces-2                         80487        80382   -0.13%
BenchmarkInterfaceByIndex-2                   72013        71391   -0.86%
BenchmarkInterfaceByName-2                    79865        80101   +0.30%
BenchmarkInterfaceAddrs-2                     42071       829677  +1872.09%
BenchmarkInterfacesAndAddrs-2                 35016       607622  +1635.27%
BenchmarkInterfacesAndMulticastAddrs-2       169849       169082   -0.45%
old: 15797:9c3930413c1b, new: tip

Benchmark results on linux/amd64, virtual machine:
benchmark                                 old ns/op    new ns/op    delta
BenchmarkInterfaces-2                         80487        81459   +1.21%
BenchmarkInterfaceByIndex-2                   72013        71512   -0.70%
BenchmarkInterfaceByName-2                    79865        80567   +0.88%
BenchmarkInterfaceAddrs-2                     42071       120108  +185.49%
BenchmarkInterfacesAndAddrs-2                 35016        33259   -5.02%
BenchmarkInterfacesAndMulticastAddrs-2       169849        82391  -51.49%
old: 15797:9c3930413c1b, new: tip+CL7400055

Benchmark results on darwin/amd64:
benchmark                                 old ns/op    new ns/op    delta
BenchmarkInterfaces-2                         34402        34231   -0.50%
BenchmarkInterfaceByIndex-2                   13192        12956   -1.79%
BenchmarkInterfaceByName-2                    34791        34388   -1.16%
BenchmarkInterfaceAddrs-2                     36565        63906  +74.77%
BenchmarkInterfacesAndAddrs-2                 17497        31068  +77.56%
BenchmarkInterfacesAndMulticastAddrs-2        25276        66711  +163.93%
old: 15797:9c3930413c1b, new: tip

Benchmark results on darwin/amd64:
benchmark                                 old ns/op    new ns/op    delta
BenchmarkInterfaces-2                         34402        31854   -7.41%
BenchmarkInterfaceByIndex-2                   13192        12950   -1.83%
BenchmarkInterfaceByName-2                    34791        31926   -8.23%
BenchmarkInterfaceAddrs-2                     36565        42144  +15.26%
BenchmarkInterfacesAndAddrs-2                 17497        17329   -0.96%
BenchmarkInterfacesAndMulticastAddrs-2        25276        24870   -1.61%
old: 15797:9c3930413c1b, new: tip+CL7400055

Update #4234.
Fixes #4839 (again).
Fixes #4866.

R=golang-dev, fullung
CC=golang-dev
https://golang.org/cl/7400055
This commit is contained in:
Mikio Hara 2013-02-28 14:58:41 +09:00
parent f0a8b610e7
commit 322214cf54
12 changed files with 366 additions and 121 deletions

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification
package net
import "errors"
@ -66,7 +64,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil {
return nil, errInvalidInterface
}
return interfaceAddrTable(ifi.Index)
return interfaceAddrTable(ifi)
}
// MulticastAddrs returns multicast, joined group addresses for
@ -75,7 +73,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil {
return nil, errInvalidInterface
}
return interfaceMulticastAddrTable(ifi.Index)
return interfaceMulticastAddrTable(ifi)
}
// Interfaces returns a list of the system's network interfaces.
@ -86,7 +84,7 @@ func Interfaces() ([]Interface, error) {
// InterfaceAddrs returns a list of the system's network interface
// addresses.
func InterfaceAddrs() ([]Addr, error) {
return interfaceAddrTable(0)
return interfaceAddrTable(nil)
}
// InterfaceByIndex returns the interface specified by index.
@ -98,8 +96,14 @@ func InterfaceByIndex(index int) (*Interface, error) {
if err != nil {
return nil, err
}
return interfaceByIndex(ift, index)
}
func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
for _, ifi := range ift {
return &ifi, nil
if index == ifi.Index {
return &ifi, nil
}
}
return nil, errNoSuchInterface
}

View File

@ -4,8 +4,6 @@
// +build darwin freebsd netbsd openbsd
// Network interface identification for BSD variants
package net
import (
@ -26,7 +24,12 @@ func interfaceTable(ifindex int) ([]Interface, error) {
if err != nil {
return nil, os.NewSyscallError("route message", err)
}
return parseInterfaceTable(ifindex, msgs)
}
func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
var ift []Interface
loop:
for _, m := range msgs {
switch m := m.(type) {
case *syscall.InterfaceMessage:
@ -35,26 +38,28 @@ func interfaceTable(ifindex int) ([]Interface, error) {
if err != nil {
return nil, err
}
ift = append(ift, ifi...)
ift = append(ift, *ifi)
if ifindex == int(m.Header.Index) {
break loop
}
}
}
}
return ift, nil
}
func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
}
var ift []Interface
ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
for _, sa := range sas {
switch sa := sa.(type) {
case *syscall.SockaddrDatalink:
// NOTE: SockaddrDatalink.Data is minimum work area,
// can be larger.
m.Data = m.Data[unsafe.Offsetof(sa.Data):]
ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
var name [syscall.IFNAMSIZ]byte
for i := 0; i < int(sa.Nlen); i++ {
name[i] = byte(m.Data[i])
@ -66,10 +71,9 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
addr[i] = byte(m.Data[int(sa.Nlen)+i])
}
ifi.HardwareAddr = addr[:sa.Alen]
ift = append(ift, ifi)
}
}
return ift, nil
return ifi, nil
}
func linkFlags(rawFlags int32) Flags {
@ -92,11 +96,15 @@ func linkFlags(rawFlags int32) Flags {
return f
}
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
// If the ifi is nil, interfaceAddrTable returns addresses for all
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
index := 0
if ifi != nil {
index = ifi.Index
}
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
if err != nil {
return nil, os.NewSyscallError("route rib", err)
}
@ -104,12 +112,26 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
if err != nil {
return nil, os.NewSyscallError("route message", err)
}
var ift []Interface
if index == 0 {
ift, err = parseInterfaceTable(index, msgs)
if err != nil {
return nil, err
}
}
var ifat []Addr
for _, m := range msgs {
switch m := m.(type) {
case *syscall.InterfaceAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) {
ifa, err := newAddr(m)
if index == 0 || index == int(m.Header.Index) {
if index == 0 {
var err error
ifi, err = interfaceByIndex(ift, int(m.Header.Index))
if err != nil {
return nil, err
}
}
ifa, err := newAddr(ifi, m)
if err != nil {
return nil, err
}
@ -122,7 +144,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
return ifat, nil
}
func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
@ -149,7 +171,7 @@ func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifa.IP.IsLinkLocalUnicast() {
ifa.Zone = zoneToString(int(ifa.IP[2]<<8 | ifa.IP[3]))
ifa.Zone = ifi.Name
ifa.IP[2], ifa.IP[3] = 0, 0
}
}

View File

@ -0,0 +1,50 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd netbsd openbsd
package net
import (
"fmt"
"os/exec"
)
func (ti *testInterface) setBroadcast(suffix int) {
ti.name = fmt.Sprintf("vlan%d", suffix)
xname, err := exec.LookPath("ifconfig")
if err != nil {
xname = "ifconfig"
}
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "create"},
})
ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "destroy"},
})
}
func (ti *testInterface) setPointToPoint(suffix int, local, remote string) {
ti.name = fmt.Sprintf("gif%d", suffix)
ti.local = local
ti.remote = remote
xname, err := exec.LookPath("ifconfig")
if err != nil {
xname = "ifconfig"
}
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "create"},
})
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "inet", ti.local, ti.remote},
})
ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "destroy"},
})
}

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for Darwin
package net
import (
@ -11,11 +9,10 @@ import (
"syscall"
)
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
if err != nil {
return nil, os.NewSyscallError("route rib", err)
}
@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
for _, m := range msgs {
switch m := m.(type) {
case *syscall.InterfaceMulticastAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) {
ifma, err := newMulticastAddr(m)
if ifi.Index == int(m.Header.Index) {
ifma, err := newMulticastAddr(ifi, m)
if err != nil {
return nil, err
}
@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return ifmat, nil
}
func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.Zone = zoneToString(int(ifma.IP[2]<<8 | ifma.IP[3]))
ifma.Zone = ifi.Name
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for FreeBSD
package net
import (
@ -11,11 +9,10 @@ import (
"syscall"
)
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
if err != nil {
return nil, os.NewSyscallError("route rib", err)
}
@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
for _, m := range msgs {
switch m := m.(type) {
case *syscall.InterfaceMulticastAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) {
ifma, err := newMulticastAddr(m)
if ifi.Index == int(m.Header.Index) {
ifma, err := newMulticastAddr(ifi, m)
if err != nil {
return nil, err
}
@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return ifmat, nil
}
func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.Zone = zoneToString(int(ifma.IP[2]<<8 | ifma.IP[3]))
ifma.Zone = ifi.Name
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for Linux
package net
import (
@ -37,16 +35,18 @@ loop:
if err != nil {
return nil, os.NewSyscallError("netlink routeattr", err)
}
ifi := newLink(ifim, attrs)
ift = append(ift, ifi)
ift = append(ift, *newLink(ifim, attrs))
if ifindex == int(ifim.Index) {
break loop
}
}
}
}
return ift, nil
}
func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFLA_ADDRESS:
@ -88,10 +88,10 @@ func linkFlags(rawFlags uint32) Flags {
return f
}
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
// If the ifi is nil, interfaceAddrTable returns addresses for all
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
if err != nil {
return nil, os.NewSyscallError("netlink rib", err)
@ -100,14 +100,22 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
if err != nil {
return nil, os.NewSyscallError("netlink message", err)
}
ifat, err := addrTable(msgs, ifindex)
var ift []Interface
if ifi == nil {
var err error
ift, err = interfaceTable(0)
if err != nil {
return nil, err
}
}
ifat, err := addrTable(ift, ifi, msgs)
if err != nil {
return nil, err
}
return ifat, nil
}
func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
var ifat []Addr
loop:
for _, m := range msgs {
@ -116,58 +124,51 @@ loop:
break loop
case syscall.RTM_NEWADDR:
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
ifi, err := InterfaceByIndex(int(ifam.Index))
if err != nil {
return nil, err
}
if ifindex == 0 || ifindex == int(ifam.Index) {
if len(ift) != 0 || ifi.Index == int(ifam.Index) {
if len(ift) != 0 {
var err error
ifi, err = interfaceByIndex(ift, int(ifam.Index))
if err != nil {
return nil, err
}
}
attrs, err := syscall.ParseNetlinkRouteAttr(&m)
if err != nil {
return nil, os.NewSyscallError("netlink routeattr", err)
}
ifat = append(ifat, newAddr(attrs, ifi, ifam))
ifa := newAddr(ifi, ifam, attrs)
if ifa != nil {
ifat = append(ifat, ifa)
}
}
}
}
return ifat, nil
}
func newAddr(attrs []syscall.NetlinkRouteAttr, ifi *Interface, ifam *syscall.IfAddrmsg) Addr {
ifa := &IPNet{}
func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
for _, a := range attrs {
if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL ||
ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS {
switch ifam.Family {
case syscall.AF_INET:
ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
ifa.Mask = CIDRMask(int(ifam.Prefixlen), 8*IPv4len)
return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
case syscall.AF_INET6:
ifa.IP = make(IP, IPv6len)
ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
copy(ifa.IP, a.Value[:])
ifa.Mask = CIDRMask(int(ifam.Prefixlen), 8*IPv6len)
if ifam.Scope == syscall.RT_SCOPE_HOST || ifam.Scope == syscall.RT_SCOPE_LINK {
ifa.Zone = zoneToString(int(ifam.Index))
ifa.Zone = ifi.Name
}
return ifa
}
}
}
return ifa
return nil
}
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
err error
ifi *Interface
)
if ifindex > 0 {
ifi, err = InterfaceByIndex(ifindex)
if err != nil {
return nil, err
}
}
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
return append(ifmat4, ifmat6...), nil

View File

@ -4,7 +4,53 @@
package net
import "testing"
import (
"fmt"
"os/exec"
"testing"
)
func (ti *testInterface) setBroadcast(suffix int) {
ti.name = fmt.Sprintf("gotest%d", suffix)
xname, err := exec.LookPath("ip")
if err != nil {
xname = "ip"
}
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ip", "link", "add", ti.name, "type", "dummy"},
})
ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
Path: xname,
Args: []string{"ip", "link", "delete", ti.name, "type", "dummy"},
})
}
func (ti *testInterface) setPointToPoint(suffix int, local, remote string) {
ti.name = fmt.Sprintf("gotest%d", suffix)
ti.local = local
ti.remote = remote
xname, err := exec.LookPath("ip")
if err != nil {
xname = "ip"
}
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ip", "tunnel", "add", ti.name, "mode", "gre", "local", local, "remote", remote},
})
ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
Path: xname,
Args: []string{"ip", "tunnel", "del", ti.name, "mode", "gre", "local", local, "remote", remote},
})
xname, err = exec.LookPath("ifconfig")
if err != nil {
xname = "ifconfig"
}
ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
Path: xname,
Args: []string{"ifconfig", ti.name, "inet", local, "dstaddr", remote},
})
}
const (
numOfTestIPv4MCAddrs = 14

View File

@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for NetBSD
package net
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms.
return nil, nil
}

View File

@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for OpenBSD
package net
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms.
return nil, nil
}

View File

@ -4,8 +4,6 @@
// +build plan9
// Network interface identification
package net
// If the ifindex is zero, interfaceTable returns mappings of all
@ -15,16 +13,15 @@ func interfaceTable(ifindex int) ([]Interface, error) {
return nil, nil
}
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
// If the ifi is nil, interfaceAddrTable returns addresses for all
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
return nil, nil
}
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
return nil, nil
}

View File

@ -0,0 +1,141 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd linux netbsd openbsd
package net
import (
"os"
"os/exec"
"runtime"
"testing"
"time"
)
type testInterface struct {
name string
local string
remote string
setupCmds []*exec.Cmd
teardownCmds []*exec.Cmd
}
func (ti *testInterface) setup() error {
for _, cmd := range ti.setupCmds {
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}
func (ti *testInterface) teardown() error {
for _, cmd := range ti.teardownCmds {
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}
func TestPointToPointInterface(t *testing.T) {
switch runtime.GOOS {
case "darwin":
t.Skipf("skipping read test on %q", runtime.GOOS)
}
if os.Getuid() != 0 {
t.Skip("skipping test; must be root")
}
local, remote := "169.254.0.1", "169.254.0.254"
ip := ParseIP(remote)
for i := 0; i < 3; i++ {
ti := &testInterface{}
ti.setPointToPoint(5963+i, local, remote)
if err := ti.setup(); err != nil {
t.Fatalf("testInterface.setup failed: %v", err)
} else {
time.Sleep(3 * time.Millisecond)
}
ift, err := Interfaces()
if err != nil {
ti.teardown()
t.Fatalf("Interfaces failed: %v", err)
}
for _, ifi := range ift {
if ti.name == ifi.Name {
ifat, err := ifi.Addrs()
if err != nil {
ti.teardown()
t.Fatalf("Interface.Addrs failed: %v", err)
}
for _, ifa := range ifat {
if ip.Equal(ifa.(*IPNet).IP) {
ti.teardown()
t.Fatalf("got %v; want %v", ip, local)
}
}
}
}
if err := ti.teardown(); err != nil {
t.Fatalf("testInterface.teardown failed: %v", err)
} else {
time.Sleep(3 * time.Millisecond)
}
}
}
func TestInterfaceArrivalAndDeparture(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("skipping test; must be root")
}
for i := 0; i < 3; i++ {
ift1, err := Interfaces()
if err != nil {
t.Fatalf("Interfaces failed: %v", err)
}
ti := &testInterface{}
ti.setBroadcast(5682 + i)
if err := ti.setup(); err != nil {
t.Fatalf("testInterface.setup failed: %v", err)
} else {
time.Sleep(3 * time.Millisecond)
}
ift2, err := Interfaces()
if err != nil {
ti.teardown()
t.Fatalf("Interfaces failed: %v", err)
}
if len(ift2) <= len(ift1) {
for _, ifi := range ift1 {
t.Logf("before: %v", ifi)
}
for _, ifi := range ift2 {
t.Logf("after: %v", ifi)
}
ti.teardown()
t.Fatalf("got %v; want gt %v", len(ift2), len(ift1))
}
if err := ti.teardown(); err != nil {
t.Fatalf("testInterface.teardown failed: %v", err)
} else {
time.Sleep(3 * time.Millisecond)
}
ift3, err := Interfaces()
if err != nil {
t.Fatalf("Interfaces failed: %v", err)
}
if len(ift3) >= len(ift2) {
for _, ifi := range ift2 {
t.Logf("before: %v", ifi)
}
for _, ifi := range ift3 {
t.Logf("after: %v", ifi)
}
t.Fatalf("got %v; want lt %v", len(ift3), len(ift2))
}
}
}

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Network interface identification for Windows
package net
import (
@ -129,10 +127,10 @@ func interfaceTable(ifindex int) ([]Interface, error) {
return ift, nil
}
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
// If the ifi is nil, interfaceAddrTable returns addresses for all
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
ai, err := getAdapterList()
if err != nil {
return nil, err
@ -141,11 +139,10 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
var ifat []Addr
for ; ai != nil; ai = ai.Next {
index := ai.Index
if ifindex == 0 || ifindex == int(index) {
if ifi == nil || ifi.Index == int(index) {
ipl := &ai.IpAddressList
for ; ipl != nil; ipl = ipl.Next {
ifa := IPAddr{}
ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
ifat = append(ifat, ifa.toAddr())
}
}
@ -153,10 +150,9 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
return ifat, nil
}
// If the ifindex is zero, interfaceMulticastAddrTable returns
// addresses for all network interfaces. Otherwise it returns
// addresses for a specific interface.
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms.
return nil, nil
}