net/netns: optimize defaultRouteInterface a bit

It'll be called a bunch, so worth a bit of effort. Could go further, but not yet.
(really, should hook into wgengine/monitor and only re-read on netlink changes?)

name                     old time/op    new time/op    delta
DefaultRouteInterface-8    60.8µs ±11%    44.6µs ± 5%  -26.65%  (p=0.000 n=20+19)

name                     old alloc/op   new alloc/op   delta
DefaultRouteInterface-8    3.29kB ± 0%    0.55kB ± 0%  -83.21%  (p=0.000 n=20+20)

name                     old allocs/op  new allocs/op  delta
DefaultRouteInterface-8      9.00 ± 0%      6.00 ± 0%  -33.33%  (p=0.000 n=20+20)
pull/427/head
Brad Fitzpatrick 5 years ago
parent 9e5d79e2f1
commit a5d6c9d616

@ -5,10 +5,12 @@
package netns package netns
import ( import (
"bufio"
"bytes"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
@ -41,17 +43,30 @@ func ipRuleAvailable() bool {
return ipRuleOnce.v return ipRuleOnce.v
} }
var zeroRouteBytes = []byte("00000000")
// defaultRouteInterface returns the name of the network interface that owns // defaultRouteInterface returns the name of the network interface that owns
// the default route, not including any tailscale interfaces. We only use // the default route, not including any tailscale interfaces. We only use
// this in SO_BINDTODEVICE mode. // this in SO_BINDTODEVICE mode.
func defaultRouteInterface() (string, error) { func defaultRouteInterface() (string, error) {
b, err := ioutil.ReadFile("/proc/net/route") f, err := os.Open("/proc/net/route")
if err != nil { if err != nil {
return "", err return "", err
} }
defer f.Close()
for _, line := range strings.Split(string(b), "\n")[1:] { br := bufio.NewReaderSize(f, 128)
fields := strings.Fields(line) for {
line, err := br.ReadSlice('\n')
if err == io.EOF {
break
}
if err != nil {
return "", err
}
if !bytes.Contains(line, zeroRouteBytes) {
continue
}
fields := strings.Fields(string(line))
ifc := fields[0] ifc := fields[0]
ip := fields[1] ip := fields[1]
netmask := fields[7] netmask := fields[7]

@ -49,3 +49,12 @@ func TestBypassMarkInSync(t *testing.T) {
} }
t.Errorf("tailscaleBypassMark not found in router_linux.go") t.Errorf("tailscaleBypassMark not found in router_linux.go")
} }
func BenchmarkDefaultRouteInterface(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if _, err := defaultRouteInterface(); err != nil {
b.Fatal(err)
}
}
}

Loading…
Cancel
Save