aboutsummaryrefslogtreecommitdiff
path: root/src/net/interface.go
diff options
context:
space:
mode:
authorMikio Hara <mikioh.mikioh@gmail.com>2016-04-13 06:19:53 +0900
committerMikio Hara <mikioh.mikioh@gmail.com>2016-04-15 01:45:27 +0000
commit1d214f7062e80bebb081cdfad2ceda3e5bd0de29 (patch)
tree5258186a65107b879efe4831d51c4e3b0c70dd72 /src/net/interface.go
parent19db74566491dcbb4dc2ad0a92b98aa2c28dd8fe (diff)
downloadgo-1d214f7062e80bebb081cdfad2ceda3e5bd0de29.tar.xz
net: cache IPv6 zone information for applications using IPv6 link-local address
This change reduces the overhead of calling routing information per IPv6 link-local datagram read by caching IPv6 addressing scope zone information. Fixes #15237. name old time/op new time/op delta UDP6LinkLocalUnicast-8 64.9µs ± 0% 18.6µs ± 0% -71.30% name old alloc/op new alloc/op delta UDP6LinkLocalUnicast-8 11.2kB ± 0% 0.2kB ± 0% -98.42% name old allocs/op new allocs/op delta UDP6LinkLocalUnicast-8 101 ± 0% 3 ± 0% -97.03% Change-Id: I5ae2ef5058df1028bbb7f4ab32b13edfb330c3a7 Reviewed-on: https://go-review.googlesource.com/21952 Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/net/interface.go')
-rw-r--r--src/net/interface.go81
1 files changed, 78 insertions, 3 deletions
diff --git a/src/net/interface.go b/src/net/interface.go
index c99f8fd216..52b857c65f 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -4,7 +4,11 @@
package net
-import "errors"
+import (
+ "errors"
+ "sync"
+ "time"
+)
var (
errInvalidInterface = errors.New("invalid network interface")
@@ -88,9 +92,12 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
func Interfaces() ([]Interface, error) {
ift, err := interfaceTable(0)
if err != nil {
- err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+ return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
}
- return ift, err
+ if len(ift) != 0 {
+ zoneCache.update(ift)
+ }
+ return ift, nil
}
// InterfaceAddrs returns a list of the system's network interface
@@ -137,6 +144,9 @@ func InterfaceByName(name string) (*Interface, error) {
if err != nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
}
+ if len(ift) != 0 {
+ zoneCache.update(ift)
+ }
for _, ifi := range ift {
if name == ifi.Name {
return &ifi, nil
@@ -144,3 +154,68 @@ func InterfaceByName(name string) (*Interface, error) {
}
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
}
+
+// An ipv6ZoneCache represents a cache holding partial network
+// interface information. It is used for reducing the cost of IPv6
+// addressing scope zone resolution.
+type ipv6ZoneCache struct {
+ sync.RWMutex // guard the following
+ lastFetched time.Time // last time routing information was fetched
+ toIndex map[string]int // interface name to its index
+ toName map[int]string // interface index to its name
+}
+
+var zoneCache = ipv6ZoneCache{
+ toIndex: make(map[string]int),
+ toName: make(map[int]string),
+}
+
+func (zc *ipv6ZoneCache) update(ift []Interface) {
+ zc.Lock()
+ defer zc.Unlock()
+ now := time.Now()
+ if zc.lastFetched.After(now.Add(-60 * time.Second)) {
+ return
+ }
+ zc.lastFetched = now
+ if len(ift) == 0 {
+ var err error
+ if ift, err = interfaceTable(0); err != nil {
+ return
+ }
+ }
+ zc.toIndex = make(map[string]int, len(ift))
+ zc.toName = make(map[int]string, len(ift))
+ for _, ifi := range ift {
+ zc.toIndex[ifi.Name] = ifi.Index
+ zc.toName[ifi.Index] = ifi.Name
+ }
+}
+
+func zoneToString(zone int) string {
+ if zone == 0 {
+ return ""
+ }
+ zoneCache.update(nil)
+ zoneCache.RLock()
+ defer zoneCache.RUnlock()
+ name, ok := zoneCache.toName[zone]
+ if !ok {
+ name = uitoa(uint(zone))
+ }
+ return name
+}
+
+func zoneToInt(zone string) int {
+ if zone == "" {
+ return 0
+ }
+ zoneCache.update(nil)
+ zoneCache.RLock()
+ defer zoneCache.RUnlock()
+ index, ok := zoneCache.toIndex[zone]
+ if !ok {
+ index, _, _ = dtoi(zone, 0)
+ }
+ return index
+}