Commit 322214cf authored by Mikio Hara's avatar Mikio Hara

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
parent f0a8b610
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification
package net package net
import "errors" import "errors"
...@@ -66,7 +64,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) { ...@@ -66,7 +64,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil { if ifi == nil {
return nil, errInvalidInterface return nil, errInvalidInterface
} }
return interfaceAddrTable(ifi.Index) return interfaceAddrTable(ifi)
} }
// MulticastAddrs returns multicast, joined group addresses for // MulticastAddrs returns multicast, joined group addresses for
...@@ -75,7 +73,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) { ...@@ -75,7 +73,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil { if ifi == nil {
return nil, errInvalidInterface return nil, errInvalidInterface
} }
return interfaceMulticastAddrTable(ifi.Index) return interfaceMulticastAddrTable(ifi)
} }
// Interfaces returns a list of the system's network interfaces. // Interfaces returns a list of the system's network interfaces.
...@@ -86,7 +84,7 @@ func Interfaces() ([]Interface, error) { ...@@ -86,7 +84,7 @@ func Interfaces() ([]Interface, error) {
// InterfaceAddrs returns a list of the system's network interface // InterfaceAddrs returns a list of the system's network interface
// addresses. // addresses.
func InterfaceAddrs() ([]Addr, error) { func InterfaceAddrs() ([]Addr, error) {
return interfaceAddrTable(0) return interfaceAddrTable(nil)
} }
// InterfaceByIndex returns the interface specified by index. // InterfaceByIndex returns the interface specified by index.
...@@ -98,9 +96,15 @@ func InterfaceByIndex(index int) (*Interface, error) { ...@@ -98,9 +96,15 @@ func InterfaceByIndex(index int) (*Interface, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return interfaceByIndex(ift, index)
}
func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
for _, ifi := range ift { for _, ifi := range ift {
if index == ifi.Index {
return &ifi, nil return &ifi, nil
} }
}
return nil, errNoSuchInterface return nil, errNoSuchInterface
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
// +build darwin freebsd netbsd openbsd // +build darwin freebsd netbsd openbsd
// Network interface identification for BSD variants
package net package net
import ( import (
...@@ -26,7 +24,12 @@ func interfaceTable(ifindex int) ([]Interface, error) { ...@@ -26,7 +24,12 @@ func interfaceTable(ifindex int) ([]Interface, error) {
if err != nil { if err != nil {
return nil, os.NewSyscallError("route message", err) return nil, os.NewSyscallError("route message", err)
} }
return parseInterfaceTable(ifindex, msgs)
}
func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
var ift []Interface var ift []Interface
loop:
for _, m := range msgs { for _, m := range msgs {
switch m := m.(type) { switch m := m.(type) {
case *syscall.InterfaceMessage: case *syscall.InterfaceMessage:
...@@ -35,26 +38,28 @@ func interfaceTable(ifindex int) ([]Interface, error) { ...@@ -35,26 +38,28 @@ func interfaceTable(ifindex int) ([]Interface, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
ift = append(ift, ifi...) ift = append(ift, *ifi)
if ifindex == int(m.Header.Index) {
break loop
}
} }
} }
} }
return ift, nil return ift, nil
} }
func newLink(m *syscall.InterfaceMessage) ([]Interface, error) { func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
sas, err := syscall.ParseRoutingSockaddr(m) sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route sockaddr", err) 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 { for _, sa := range sas {
switch sa := sa.(type) { switch sa := sa.(type) {
case *syscall.SockaddrDatalink: case *syscall.SockaddrDatalink:
// NOTE: SockaddrDatalink.Data is minimum work area, // NOTE: SockaddrDatalink.Data is minimum work area,
// can be larger. // can be larger.
m.Data = m.Data[unsafe.Offsetof(sa.Data):] 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 var name [syscall.IFNAMSIZ]byte
for i := 0; i < int(sa.Nlen); i++ { for i := 0; i < int(sa.Nlen); i++ {
name[i] = byte(m.Data[i]) name[i] = byte(m.Data[i])
...@@ -66,10 +71,9 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) { ...@@ -66,10 +71,9 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
addr[i] = byte(m.Data[int(sa.Nlen)+i]) addr[i] = byte(m.Data[int(sa.Nlen)+i])
} }
ifi.HardwareAddr = addr[:sa.Alen] ifi.HardwareAddr = addr[:sa.Alen]
ift = append(ift, ifi)
} }
} }
return ift, nil return ifi, nil
} }
func linkFlags(rawFlags int32) Flags { func linkFlags(rawFlags int32) Flags {
...@@ -92,11 +96,15 @@ func linkFlags(rawFlags int32) Flags { ...@@ -92,11 +96,15 @@ func linkFlags(rawFlags int32) Flags {
return f return f
} }
// If the ifindex is zero, interfaceAddrTable returns addresses // If the ifi is nil, interfaceAddrTable returns addresses for all
// for all network interfaces. Otherwise it returns addresses // network interfaces. Otherwise it returns addresses for a specific
// for a specific interface. // interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) { func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) index := 0
if ifi != nil {
index = ifi.Index
}
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route rib", err) return nil, os.NewSyscallError("route rib", err)
} }
...@@ -104,12 +112,26 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { ...@@ -104,12 +112,26 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
if err != nil { if err != nil {
return nil, os.NewSyscallError("route message", err) 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 var ifat []Addr
for _, m := range msgs { for _, m := range msgs {
switch m := m.(type) { switch m := m.(type) {
case *syscall.InterfaceAddrMessage: case *syscall.InterfaceAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) { if index == 0 || index == int(m.Header.Index) {
ifa, err := newAddr(m) 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 { if err != nil {
return nil, err return nil, err
} }
...@@ -122,7 +144,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { ...@@ -122,7 +144,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
return ifat, nil return ifat, nil
} }
func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) { func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m) sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route sockaddr", err) return nil, os.NewSyscallError("route sockaddr", err)
...@@ -149,7 +171,7 @@ func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) { ...@@ -149,7 +171,7 @@ func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
// the interface index in the interface-local or link- // the interface index in the interface-local or link-
// local address as the kernel-internal form. // local address as the kernel-internal form.
if ifa.IP.IsLinkLocalUnicast() { 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 ifa.IP[2], ifa.IP[3] = 0, 0
} }
} }
......
// 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 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for Darwin
package net package net
import ( import (
...@@ -11,11 +9,10 @@ import ( ...@@ -11,11 +9,10 @@ import (
"syscall" "syscall"
) )
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route rib", err) return nil, os.NewSyscallError("route rib", err)
} }
...@@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { ...@@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
for _, m := range msgs { for _, m := range msgs {
switch m := m.(type) { switch m := m.(type) {
case *syscall.InterfaceMulticastAddrMessage: case *syscall.InterfaceMulticastAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) { if ifi.Index == int(m.Header.Index) {
ifma, err := newMulticastAddr(m) ifma, err := newMulticastAddr(ifi, m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { ...@@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return ifmat, nil return ifmat, nil
} }
func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m) sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route sockaddr", err) return nil, os.NewSyscallError("route sockaddr", err)
...@@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) ...@@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
// the interface index in the interface-local or link- // the interface index in the interface-local or link-
// local address as the kernel-internal form. // local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { 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 ifma.IP[2], ifma.IP[3] = 0, 0
} }
ifmat = append(ifmat, ifma.toAddr()) ifmat = append(ifmat, ifma.toAddr())
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for FreeBSD
package net package net
import ( import (
...@@ -11,11 +9,10 @@ import ( ...@@ -11,11 +9,10 @@ import (
"syscall" "syscall"
) )
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route rib", err) return nil, os.NewSyscallError("route rib", err)
} }
...@@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { ...@@ -27,8 +24,8 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
for _, m := range msgs { for _, m := range msgs {
switch m := m.(type) { switch m := m.(type) {
case *syscall.InterfaceMulticastAddrMessage: case *syscall.InterfaceMulticastAddrMessage:
if ifindex == 0 || ifindex == int(m.Header.Index) { if ifi.Index == int(m.Header.Index) {
ifma, err := newMulticastAddr(m) ifma, err := newMulticastAddr(ifi, m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { ...@@ -39,7 +36,7 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return ifmat, nil return ifmat, nil
} }
func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
sas, err := syscall.ParseRoutingSockaddr(m) sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil { if err != nil {
return nil, os.NewSyscallError("route sockaddr", err) return nil, os.NewSyscallError("route sockaddr", err)
...@@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) ...@@ -57,7 +54,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
// the interface index in the interface-local or link- // the interface index in the interface-local or link-
// local address as the kernel-internal form. // local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { 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 ifma.IP[2], ifma.IP[3] = 0, 0
} }
ifmat = append(ifmat, ifma.toAddr()) ifmat = append(ifmat, ifma.toAddr())
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for Linux
package net package net
import ( import (
...@@ -37,16 +35,18 @@ loop: ...@@ -37,16 +35,18 @@ loop:
if err != nil { if err != nil {
return nil, os.NewSyscallError("netlink routeattr", err) return nil, os.NewSyscallError("netlink routeattr", err)
} }
ifi := newLink(ifim, attrs) ift = append(ift, *newLink(ifim, attrs))
ift = append(ift, ifi) if ifindex == int(ifim.Index) {
break loop
}
} }
} }
} }
return ift, nil return ift, nil
} }
func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface { func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)} ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs { for _, a := range attrs {
switch a.Attr.Type { switch a.Attr.Type {
case syscall.IFLA_ADDRESS: case syscall.IFLA_ADDRESS:
...@@ -88,10 +88,10 @@ func linkFlags(rawFlags uint32) Flags { ...@@ -88,10 +88,10 @@ func linkFlags(rawFlags uint32) Flags {
return f return f
} }
// If the ifindex is zero, interfaceAddrTable returns addresses // If the ifi is nil, interfaceAddrTable returns addresses for all
// for all network interfaces. Otherwise it returns addresses // network interfaces. Otherwise it returns addresses for a specific
// for a specific interface. // interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) { func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
if err != nil { if err != nil {
return nil, os.NewSyscallError("netlink rib", err) return nil, os.NewSyscallError("netlink rib", err)
...@@ -100,14 +100,22 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { ...@@ -100,14 +100,22 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
if err != nil { if err != nil {
return nil, os.NewSyscallError("netlink message", err) 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 { if err != nil {
return nil, err return nil, err
} }
return ifat, nil 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 var ifat []Addr
loop: loop:
for _, m := range msgs { for _, m := range msgs {
...@@ -116,58 +124,51 @@ loop: ...@@ -116,58 +124,51 @@ loop:
break loop break loop
case syscall.RTM_NEWADDR: case syscall.RTM_NEWADDR:
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
ifi, err := InterfaceByIndex(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 { if err != nil {
return nil, err return nil, err
} }
if ifindex == 0 || ifindex == int(ifam.Index) { }
attrs, err := syscall.ParseNetlinkRouteAttr(&m) attrs, err := syscall.ParseNetlinkRouteAttr(&m)
if err != nil { if err != nil {
return nil, os.NewSyscallError("netlink routeattr", err) 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 return ifat, nil
} }
func newAddr(attrs []syscall.NetlinkRouteAttr, ifi *Interface, ifam *syscall.IfAddrmsg) Addr { func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
ifa := &IPNet{}
for _, a := range attrs { for _, a := range attrs {
if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL || if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL ||
ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS { ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS {
switch ifam.Family { switch ifam.Family {
case syscall.AF_INET: case syscall.AF_INET:
ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]) return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
ifa.Mask = CIDRMask(int(ifam.Prefixlen), 8*IPv4len)
case syscall.AF_INET6: 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[:]) 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 { 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 // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
err error
ifi *Interface
)
if ifindex > 0 {
ifi, err = InterfaceByIndex(ifindex)
if err != nil {
return nil, err
}
}
ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi) ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi) ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
return append(ifmat4, ifmat6...), nil return append(ifmat4, ifmat6...), nil
......
...@@ -4,7 +4,53 @@ ...@@ -4,7 +4,53 @@
package net 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 ( const (
numOfTestIPv4MCAddrs = 14 numOfTestIPv4MCAddrs = 14
......
...@@ -2,14 +2,11 @@ ...@@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for NetBSD
package net package net
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms. // TODO(mikio): Implement this like other platforms.
return nil, nil return nil, nil
} }
...@@ -2,14 +2,11 @@ ...@@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for OpenBSD
package net package net
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms. // TODO(mikio): Implement this like other platforms.
return nil, nil return nil, nil
} }
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
// +build plan9 // +build plan9
// Network interface identification
package net package net
// If the ifindex is zero, interfaceTable returns mappings of all // If the ifindex is zero, interfaceTable returns mappings of all
...@@ -15,16 +13,15 @@ func interfaceTable(ifindex int) ([]Interface, error) { ...@@ -15,16 +13,15 @@ func interfaceTable(ifindex int) ([]Interface, error) {
return nil, nil return nil, nil
} }
// If the ifindex is zero, interfaceAddrTable returns addresses // If the ifi is nil, interfaceAddrTable returns addresses for all
// for all network interfaces. Otherwise it returns addresses // network interfaces. Otherwise it returns addresses for a specific
// for a specific interface. // interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) { func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
return nil, nil return nil, nil
} }
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, nil return nil, nil
} }
// 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 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Network interface identification for Windows
package net package net
import ( import (
...@@ -129,10 +127,10 @@ func interfaceTable(ifindex int) ([]Interface, error) { ...@@ -129,10 +127,10 @@ func interfaceTable(ifindex int) ([]Interface, error) {
return ift, nil return ift, nil
} }
// If the ifindex is zero, interfaceAddrTable returns addresses // If the ifi is nil, interfaceAddrTable returns addresses for all
// for all network interfaces. Otherwise it returns addresses // network interfaces. Otherwise it returns addresses for a specific
// for a specific interface. // interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) { func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
ai, err := getAdapterList() ai, err := getAdapterList()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -141,11 +139,10 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { ...@@ -141,11 +139,10 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
var ifat []Addr var ifat []Addr
for ; ai != nil; ai = ai.Next { for ; ai != nil; ai = ai.Next {
index := ai.Index index := ai.Index
if ifindex == 0 || ifindex == int(index) { if ifi == nil || ifi.Index == int(index) {
ipl := &ai.IpAddressList ipl := &ai.IpAddressList
for ; ipl != nil; ipl = ipl.Next { for ; ipl != nil; ipl = ipl.Next {
ifa := IPAddr{} ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
ifat = append(ifat, ifa.toAddr()) ifat = append(ifat, ifa.toAddr())
} }
} }
...@@ -153,10 +150,9 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { ...@@ -153,10 +150,9 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
return ifat, nil return ifat, nil
} }
// If the ifindex is zero, interfaceMulticastAddrTable returns // interfaceMulticastAddrTable returns addresses for a specific
// addresses for all network interfaces. Otherwise it returns // interface.
// addresses for a specific interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
// TODO(mikio): Implement this like other platforms. // TODO(mikio): Implement this like other platforms.
return nil, nil return nil, nil
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment