Merge "veyron/services/mgmt/device: Add arm and x86 profiles."
diff --git a/lib/netstate/netstate.go b/lib/netstate/netstate.go
index e188525..2cbb35b 100644
--- a/lib/netstate/netstate.go
+++ b/lib/netstate/netstate.go
@@ -155,23 +155,7 @@
 	if err != nil {
 		return nil, err
 	}
-	return all.Map(accessibleIPHost), nil
-}
-
-func accessibleIPHost(a ipc.Address) ipc.Address {
-	if !IsAccessibleIP(a) {
-		return nil
-	}
-	aifc, ok := a.(*AddrIfc)
-	if !ok {
-		return nil
-	}
-	ip := AsIPAddr(aifc.Addr)
-	if ip == nil {
-		return aifc
-	}
-	aifc.Addr = ip
-	return aifc
+	return all.Map(ConvertAccessibleIPHost), nil
 }
 
 // AddressPredicate defines the function signature for predicate functions
@@ -205,8 +189,8 @@
 	return ral
 }
 
-// Convert the network address component of an ipc.Address into an instance
-// with a net.Addr that contains an IP host address (as opposed to a
+// ConvertToIPHost converts the network address component of an ipc.Address into
+// an instance with a net.Addr that contains an IP host address (as opposed to a
 // network CIDR for example).
 func ConvertToIPHost(a ipc.Address) ipc.Address {
 	aifc, ok := a.(*AddrIfc)
@@ -217,11 +201,28 @@
 	return aifc
 }
 
+// ConvertAccessibleIPHost converts the network address component of an ipc.Address
+// into an instance with a net.Addr that contains an IP host address (as opposed to a
+// network CIDR for example) with filtering out a loopback or non-accessible IPs.
+func ConvertAccessibleIPHost(a ipc.Address) ipc.Address {
+	if !IsAccessibleIP(a) {
+		return nil
+	}
+	aifc, ok := a.(*AddrIfc)
+	if !ok {
+		return nil
+	}
+	if ip := AsIPAddr(aifc.Addr); ip != nil {
+		aifc.Addr = ip
+	}
+	return aifc
+}
+
 // IsIPProtocol returns true if its parameter is one of the allowed
 // network/protocol values for IP.
 func IsIPProtocol(n string) bool {
 	switch n {
-	case "ip+net", "ip", "tcp", "tcp4", "tcp6", "udp":
+	case "ip+net", "ip", "tcp", "tcp4", "tcp6", "udp", "wsh":
 		return true
 	default:
 		return false
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index cfc6bdc..de89583 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -95,6 +95,11 @@
 	vcOpts             []stream.VCOpt // vc opts passed to dial
 	preferredProtocols []string
 
+	// We cache the IP networks on the device since it is not that cheap to read
+	// network interfaces through os syscall.
+	// TODO(jhahn): Add monitoring the network interface changes.
+	ipNets []*net.IPNet
+
 	// We support concurrent calls to StartCall and Close, so we must protect the
 	// vcMap.  Everything else is initialized upon client construction, and safe
 	// to use concurrently.
@@ -121,6 +126,7 @@
 	c := &client{
 		streamMgr: streamMgr,
 		ns:        ns,
+		ipNets:    ipNetworks(),
 		vcMap:     make(map[vcMapKey]*vcInfo),
 	}
 	c.dc = InternalNewDischargeClient(nil, c)
@@ -421,7 +427,7 @@
 			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
 		}
 		// An empty set of protocols means all protocols...
-		if resolved.Servers, err = filterAndOrderServers(resolved.Servers, c.preferredProtocols); err != nil {
+		if resolved.Servers, err = filterAndOrderServers(resolved.Servers, c.preferredProtocols, c.ipNets); err != nil {
 			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name, err)
 		}
 	}
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index abf18a3..26fd9f0 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -58,8 +58,12 @@
 	active             sync.WaitGroup // active goroutines we've spawned.
 	stoppedChan        chan struct{}  // closed when the server has been stopped.
 	preferredProtocols []string       // protocols to use when resolving proxy name to endpoint.
-	ns                 naming.Namespace
-	servesMountTable   bool
+	// We cache the IP networks on the device since it is not that cheap to read
+	// network interfaces through os syscall.
+	// TODO(jhahn): Add monitoring the network interface changes.
+	ipNets           []*net.IPNet
+	ns               naming.Namespace
+	servesMountTable bool
 	// TODO(cnicolaou): add roaming stats to ipcStats
 	stats *ipcStats // stats for this server.
 }
@@ -145,6 +149,7 @@
 		proxies:       make(map[string]proxyState),
 		dhcpListeners: make(map[*dhcpListener]struct{}),
 		stoppedChan:   make(chan struct{}),
+		ipNets:        ipNetworks(),
 		ns:            ns,
 		stats:         newIPCStats(statsPrefix),
 	}
@@ -222,7 +227,7 @@
 		}}
 	}
 	// An empty set of protocols means all protocols...
-	if resolved.Servers, err = filterAndOrderServers(resolved.Servers, s.preferredProtocols); err != nil {
+	if resolved.Servers, err = filterAndOrderServers(resolved.Servers, s.preferredProtocols, s.ipNets); err != nil {
 		return "", err
 	}
 	for _, n := range resolved.Names() {
diff --git a/runtimes/google/ipc/sort_endpoints.go b/runtimes/google/ipc/sort_endpoints.go
index 93b8af0..53817fa 100644
--- a/runtimes/google/ipc/sort_endpoints.go
+++ b/runtimes/google/ipc/sort_endpoints.go
@@ -92,13 +92,12 @@
 // will be used, but unlike the previous case, any servers that don't support
 // these protocols will be returned also, but following the default
 // preferences.
-func filterAndOrderServers(servers []naming.MountedServer, protocols []string) ([]naming.MountedServer, error) {
+func filterAndOrderServers(servers []naming.MountedServer, protocols []string, ipnets []*net.IPNet) ([]naming.MountedServer, error) {
 	vlog.VI(3).Infof("filterAndOrderServers%v: %v", protocols, servers)
 	var (
 		errs       = newErrorAccumulator()
 		list       = make(sortableServerList, 0, len(servers))
 		protoRanks = mkProtocolRankMap(protocols)
-		ipnets     = ipNetworks()
 	)
 	if len(protoRanks) == 0 {
 		protoRanks = defaultPreferredProtocolOrder
@@ -175,6 +174,30 @@
 	return 0, fmt.Errorf("undesired protocol %q", protocol)
 }
 
+// locality returns the serverLocality to use given an endpoint and the
+// set of IP networks configured on this machine.
+func locality(ep naming.Endpoint, ipnets []*net.IPNet) serverLocality {
+	if len(ipnets) < 1 {
+		return unknownNetwork // 0 IP networks, locality doesn't matter.
+
+	}
+	host, _, err := net.SplitHostPort(ep.Addr().String())
+	if err != nil {
+		host = ep.Addr().String()
+	}
+	ip := net.ParseIP(host)
+	if ip == nil {
+		// Not an IP address (possibly not an IP network).
+		return unknownNetwork
+	}
+	for _, ipnet := range ipnets {
+		if ipnet.Contains(ip) {
+			return localNetwork
+		}
+	}
+	return remoteNetwork
+}
+
 // ipNetworks returns the IP networks on this machine.
 func ipNetworks() []*net.IPNet {
 	ifcs, err := netstate.GetAll()
@@ -193,27 +216,3 @@
 	}
 	return ret
 }
-
-// locality returns the serverLocality to use given an endpoint and the
-// set of IP networks configured on this machine.
-func locality(ep naming.Endpoint, networks []*net.IPNet) serverLocality {
-	if len(networks) < 1 {
-		return unknownNetwork // 0 IP networks, locality doesn't matter.
-
-	}
-	host, _, err := net.SplitHostPort(ep.Addr().String())
-	if err != nil {
-		host = ep.Addr().String()
-	}
-	ip := net.ParseIP(host)
-	if ip == nil {
-		// Not an IP address (possibly not an IP network).
-		return unknownNetwork
-	}
-	for _, ipnet := range networks {
-		if ipnet.Contains(ip) {
-			return localNetwork
-		}
-	}
-	return remoteNetwork
-}
diff --git a/runtimes/google/ipc/sort_internal_test.go b/runtimes/google/ipc/sort_internal_test.go
index 041cacd..f7a1419 100644
--- a/runtimes/google/ipc/sort_internal_test.go
+++ b/runtimes/google/ipc/sort_internal_test.go
@@ -1,6 +1,7 @@
 package ipc
 
 import (
+	"net"
 	"reflect"
 	"strings"
 	"testing"
@@ -17,7 +18,7 @@
 func TestIncompatible(t *testing.T) {
 	servers := []naming.MountedServer{}
 
-	_, err := filterAndOrderServers(servers, []string{"tcp"})
+	_, err := filterAndOrderServers(servers, []string{"tcp"}, nil)
 	if err == nil || err.Error() != "failed to find any compatible servers: " {
 		t.Errorf("expected a different error: %v", err)
 	}
@@ -28,7 +29,7 @@
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
 
-	_, err = filterAndOrderServers(servers, []string{"tcp"})
+	_, err = filterAndOrderServers(servers, []string{"tcp"}, nil)
 	if err == nil || (!strings.HasPrefix(err.Error(), "failed to find any compatible servers:") && !strings.Contains(err.Error(), "No compatible IPC versions available")) {
 		t.Errorf("expected a different error to: %v", err)
 	}
@@ -38,7 +39,7 @@
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
 
-	_, err = filterAndOrderServers(servers, []string{"foobar"})
+	_, err = filterAndOrderServers(servers, []string{"foobar"}, nil)
 	if err == nil || !strings.HasSuffix(err.Error(), "undesired protocol \"tcp\")") {
 		t.Errorf("expected a different error to: %v", err)
 	}
@@ -47,6 +48,9 @@
 
 func TestOrderingByProtocol(t *testing.T) {
 	servers := []naming.MountedServer{}
+	_, ipnet, _ := net.ParseCIDR("127.0.0.0/8")
+	ipnets := []*net.IPNet{ipnet}
+
 	for _, a := range []string{"127.0.0.3", "127.0.0.4"} {
 		name := naming.JoinAddressName(naming.FormatEndpoint("tcp", a), "")
 		servers = append(servers, naming.MountedServer{Server: name})
@@ -63,7 +67,7 @@
 		name := naming.JoinAddressName(naming.FormatEndpoint("tcp6", a), "")
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
-	if _, err := filterAndOrderServers(servers, []string{"batman"}); err == nil {
+	if _, err := filterAndOrderServers(servers, []string{"batman"}, ipnets); err == nil {
 		t.Fatalf("expected an error")
 	}
 
@@ -82,7 +86,7 @@
 		"/@2@tcp4@127.0.0.2@@@@@",
 		"/127.0.0.12:14141",
 	}
-	result, err := filterAndOrderServers(servers, []string{"foobar", "tcp4"})
+	result, err := filterAndOrderServers(servers, []string{"foobar", "tcp4"}, ipnets)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -106,14 +110,14 @@
 		"/@2@foobar@127.0.0.11@@@@@",
 		"/127.0.0.12:14141",
 	}
-	if result, err = filterAndOrderServers(servers, nil); err != nil {
+	if result, err = filterAndOrderServers(servers, nil, ipnets); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	if got := servers2names(result); !reflect.DeepEqual(got, want) {
 		t.Errorf("got: %v, want %v", got, want)
 	}
 
-	if result, err = filterAndOrderServers(servers, []string{}); err != nil {
+	if result, err = filterAndOrderServers(servers, []string{}, ipnets); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	if got := servers2names(result); !reflect.DeepEqual(got, want) {
@@ -130,7 +134,7 @@
 		"/@2@tcp6@127.0.0.8@@@@@",
 		"/127.0.0.12:14141",
 	}
-	if result, err = filterAndOrderServers(servers, []string{"tcp"}); err != nil {
+	if result, err = filterAndOrderServers(servers, []string{"tcp"}, ipnets); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	if got := servers2names(result); !reflect.DeepEqual(got, want) {
@@ -159,7 +163,7 @@
 		name := naming.JoinAddressName(naming.FormatEndpoint("foobar", a), "")
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
-	if result, err = filterAndOrderServers(servers, []string{}); err != nil {
+	if result, err = filterAndOrderServers(servers, []string{}, ipnets); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	if got := servers2names(result); !reflect.DeepEqual(got, want) {
@@ -169,11 +173,14 @@
 
 func TestOrderingByLocality(t *testing.T) {
 	servers := []naming.MountedServer{}
+	_, ipnet, _ := net.ParseCIDR("127.0.0.0/8")
+	ipnets := []*net.IPNet{ipnet}
+
 	for _, a := range []string{"74.125.69.139", "127.0.0.3", "127.0.0.1", "192.168.1.10", "74.125.142.83"} {
 		name := naming.JoinAddressName(naming.FormatEndpoint("tcp", a), "")
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
-	result, err := filterAndOrderServers(servers, []string{"tcp"})
+	result, err := filterAndOrderServers(servers, []string{"tcp"}, ipnets)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -192,7 +199,7 @@
 		servers = append(servers, naming.MountedServer{Server: name})
 	}
 
-	if result, err = filterAndOrderServers(servers, []string{"ws", "tcp"}); err != nil {
+	if result, err = filterAndOrderServers(servers, []string{"ws", "tcp"}, ipnets); err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	want = []string{
diff --git a/services/mgmt/stats/impl/stats.go b/services/mgmt/stats/impl/stats.go
index c4d2277..f73d8e5 100644
--- a/services/mgmt/stats/impl/stats.go
+++ b/services/mgmt/stats/impl/stats.go
@@ -10,7 +10,6 @@
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/naming"
 	"v.io/core/veyron2/services/mgmt/stats"
-	"v.io/core/veyron2/services/mgmt/stats/types"
 	"v.io/core/veyron2/services/watch"
 	watchtypes "v.io/core/veyron2/services/watch/types"
 	"v.io/core/veyron2/vdl"
@@ -26,7 +25,7 @@
 const pkgPath = "v.io/core/veyron/services/mgmt/stats/impl"
 
 var (
-	errNoValue         = verror.Register(types.NoValue, verror.NoRetry, "{1:}{2:} object has no value{:_}")
+	errNoValue         = verror.Register(stats.NoValue, verror.NoRetry, "{1:}{2:} object has no value{:_}")
 	errOperationFailed = verror.Register(pkgPath+".errOperationFailed", verror.NoRetry, "{1:}{2:} operation failed{:_}")
 )