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:
parent
f0a8b610e7
commit
322214cf54
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
50
src/pkg/net/interface_bsd_test.go
Normal file
50
src/pkg/net/interface_bsd_test.go
Normal 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"},
|
||||
})
|
||||
}
|
@ -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())
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
141
src/pkg/net/interface_unix_test.go
Normal file
141
src/pkg/net/interface_unix_test.go
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user