veyron/lib/netstate,netconfig: move netconfig out of the runtime and create netstate.
netstate is a set of routines for determining current networking state
and making policy based selections from the set of available addresses.
Change-Id: Iba2e20f046ae6018bd14f4fcb66f3d1c17af1518
diff --git a/examples/netconfigwatcher/main.go b/examples/netconfigwatcher/main.go
index b935883..5716d5d 100644
--- a/examples/netconfigwatcher/main.go
+++ b/examples/netconfigwatcher/main.go
@@ -4,7 +4,7 @@
"fmt"
"log"
- "veyron/runtimes/google/lib/netconfig"
+ "veyron/lib/netconfig"
)
func main() {
diff --git a/runtimes/google/lib/netconfig/example_test.go b/lib/netconfig/example_test.go
similarity index 88%
rename from runtimes/google/lib/netconfig/example_test.go
rename to lib/netconfig/example_test.go
index 0acef69..56b0cbd 100644
--- a/runtimes/google/lib/netconfig/example_test.go
+++ b/lib/netconfig/example_test.go
@@ -4,7 +4,7 @@
"fmt"
"log"
- "veyron/runtimes/google/lib/netconfig"
+ "veyron/lib/netconfig"
)
func ExampleNetConfigWatcher() {
diff --git a/runtimes/google/lib/netconfig/ipaux.go b/lib/netconfig/ipaux.go
similarity index 100%
rename from runtimes/google/lib/netconfig/ipaux.go
rename to lib/netconfig/ipaux.go
diff --git a/runtimes/google/lib/netconfig/ipaux_bsd.go b/lib/netconfig/ipaux_bsd.go
similarity index 100%
rename from runtimes/google/lib/netconfig/ipaux_bsd.go
rename to lib/netconfig/ipaux_bsd.go
diff --git a/runtimes/google/lib/netconfig/ipaux_linux.go b/lib/netconfig/ipaux_linux.go
similarity index 100%
rename from runtimes/google/lib/netconfig/ipaux_linux.go
rename to lib/netconfig/ipaux_linux.go
diff --git a/runtimes/google/lib/netconfig/model.go b/lib/netconfig/model.go
similarity index 100%
rename from runtimes/google/lib/netconfig/model.go
rename to lib/netconfig/model.go
diff --git a/runtimes/google/lib/netconfig/isgloballyroutable.go b/lib/netstate/isgloballyroutable.go
similarity index 90%
rename from runtimes/google/lib/netconfig/isgloballyroutable.go
rename to lib/netstate/isgloballyroutable.go
index 4fa5916..ee6bae5 100644
--- a/runtimes/google/lib/netconfig/isgloballyroutable.go
+++ b/lib/netstate/isgloballyroutable.go
@@ -1,4 +1,4 @@
-package netconfig
+package netstate
import (
"net"
@@ -11,7 +11,7 @@
}
// IsGloballyRoutable returns true if the argument is a globally routable IP address.
-func IsGloballyRoutable(ip net.IP) bool {
+func IsGloballyRoutableIP(ip net.IP) bool {
if !ip.IsGlobalUnicast() {
return false
}
diff --git a/runtimes/google/lib/netconfig/isgloballyroutable_test.go b/lib/netstate/isgloballyroutable_test.go
similarity index 88%
rename from runtimes/google/lib/netconfig/isgloballyroutable_test.go
rename to lib/netstate/isgloballyroutable_test.go
index 3cce082..dd0885a 100644
--- a/runtimes/google/lib/netconfig/isgloballyroutable_test.go
+++ b/lib/netstate/isgloballyroutable_test.go
@@ -1,4 +1,4 @@
-package netconfig
+package netstate
import (
"net"
@@ -24,7 +24,7 @@
}
for _, test := range tests {
ip := net.ParseIP(test.ip)
- if got := IsGloballyRoutable(ip); got != test.want {
+ if got := IsGloballyRoutableIP(ip); got != test.want {
t.Fatalf("%s: want %v got %v", test.ip, test.want, got)
}
}
diff --git a/lib/netstate/netstate.go b/lib/netstate/netstate.go
new file mode 100644
index 0000000..e35e595
--- /dev/null
+++ b/lib/netstate/netstate.go
@@ -0,0 +1,270 @@
+// Package netstate provides routines to obtain the available set of
+// of network addresess, for determining changes to those addresses and for
+// selecting from amongst them according to some set of policies that are
+// implemented by applying simple predicates (functions with names of the form
+// Is<condition> to filter or find the first matching address from a list
+// of addresses. The intent is to make it easy to create policies that do
+// things like 'find the first IPv4 unicast address that is globally routable,
+// failing that use a private IPv4 address, and failing that, an IPv6 address'.
+//
+// A typical usage would be:
+//
+// state, _ := netstate.GetAccessibleIPs()
+// first := netstate.First(netstate.IsPublicIPv4)
+// // first will contain the first public IPv4 address or be nil.
+//
+// The example policy described above would be implemented using a
+// series of calls to First with appropriate predicates.
+//
+// Although most commercial networking hardware supports IPv6, some consumer
+// devices and more importantly many ISPs do not, so routines are provided
+// to allow developers to easily distinguish between the two and to use
+// whichever is appropriate for their product/situation.
+//
+// The term 'accessible' is used to refer to any non-loopback IP address.
+// The term 'public' is used to refer to any globally routable IP address.
+//
+// All IPv6 addresses are intended to be 'public', but any starting with
+// fc00::/7 are (RFC4193) are reserved for private use, but the go
+// net libraries do not appear to recognise this. Similarly fe80::/10
+// (RFC 4291) are reserved for 'site-local' usage, but again this is not
+// implemented in the go libraries. Any developer who needs to distinguish
+// these cases will need to write their own routines to test for them.
+//
+// When using the go net package it is important to remember that IPv6
+// addresses subsume IPv4 and hence in many cases the same internal
+// representation is used for both, thus testing for the length of the IP
+// address is unreliable. The reliable test is to use the net.To4() which
+// will return a non-nil result if can be used as an IPv4 one. Any address
+// can be used as an IPv6 and hence the only reliable way to test for an IPv6
+// address that is not an IPv4 one also is for the To4 call to return nil for
+// it.
+package netstate
+
+import (
+ "fmt"
+ "net"
+ "strings"
+)
+
+type AddrList []net.Addr
+
+func (al AddrList) String() string {
+ r := ""
+ for _, v := range al {
+ r += fmt.Sprintf("(%s) ", v)
+ }
+ return strings.TrimRight(r, " ")
+}
+
+// GetAll gets all of the available addresses on the device, including
+// loopback addresses.
+func GetAll() (AddrList, error) {
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ var all AddrList
+ for _, ifc := range interfaces {
+ addrs, err := ifc.Addrs()
+ if err != nil {
+ continue
+ }
+ all = append(all, addrs...)
+ }
+ return all, nil
+}
+
+// GetAccessibleIPs returns all of the IP addresses on the device that are
+// accessible to other devices - i.e. excluding loopback etc.
+func GetAccessibleIPs() (AddrList, error) {
+ all, err := GetAll()
+ if err != nil {
+ return nil, err
+ }
+ return all.Filter(IsAccessibleIP), nil
+}
+
+type Predicate func(a net.Addr) bool
+
+// Filter returns all of the addresses for which the predicate
+// function is true.
+func (al AddrList) Filter(predicate Predicate) AddrList {
+ r := AddrList{}
+ for _, a := range al {
+ if predicate(a) {
+ r = append(r, a)
+ }
+ }
+ return r
+}
+
+// Filter returns the first address for which the predicate function is true.
+func (al AddrList) First(predicate Predicate) net.Addr {
+ for _, a := range al {
+ if predicate(a) {
+ return a
+ }
+ }
+ return nil
+}
+
+func IsIPNetwork(n string) bool {
+ switch n {
+ case "ip+net", "tcp", "tcp4", "tcp6", "udp":
+ return true
+ default:
+ return false
+
+ }
+}
+
+// AsIP returns its argument as a net.IP if that's possible.
+func AsIP(a net.Addr) net.IP {
+ ipn, ok := a.(*net.IPNet)
+ if ok {
+ return ipn.IP
+ }
+ ipa, ok := a.(*net.IPAddr)
+ if ok {
+ return ipa.IP
+ }
+ switch a.Network() {
+ default:
+ return nil
+ case "ip+net", "tcp", "tcp4", "tcp6", "udp":
+ }
+ return net.ParseIP(a.String())
+}
+
+// IsUnspecified returns true if its argument is an unspecified IP address
+func IsUnspecifiedIP(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil {
+ return ip.IsUnspecified()
+ }
+ return false
+}
+
+// IsLoopback returns true if its argument is a loopback IP address
+func IsLoopbackIP(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && !ip.IsUnspecified() {
+ return ip.IsLoopback()
+ }
+ return false
+}
+
+// IsAccessible returns true if its argument is an accessible (non-loopback)
+// IP address.
+func IsAccessibleIP(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && !ip.IsUnspecified() {
+ return !ip.IsLoopback()
+ }
+ return false
+}
+
+type ma struct {
+ n, a string
+}
+
+func (a *ma) Network() string {
+ return a.n
+}
+
+func (a *ma) String() string {
+ return a.a
+}
+
+// AsAddr returns its argument as a net.Addr.
+func AsAddr(network string, a net.IP) net.Addr {
+ return &ma{n: network, a: a.String()}
+}
+
+// IsUnicastIP returns true if its argument is a unicast IP address.
+func IsUnicastIP(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && !ip.IsUnspecified() {
+ // ipv4 or v6
+ return !(ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast())
+ }
+ return false
+}
+
+// IsUnicastIPv4 returns true if its argument is a unicast IP4 address
+func IsUnicastIPv4(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && ip.To4() != nil && !ip.IsMulticast() {
+ return !ip.IsUnspecified() && !ip.IsMulticast()
+ }
+ return false
+}
+
+// IsPublicUnicastIPv4 returns true if its argument is a globally routable,
+// public IPv4 unicast address.
+func IsPublicUnicastIPv4(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && !ip.IsUnspecified() {
+ if t := ip.To4(); t != nil && IsGloballyRoutableIP(t) {
+ return !ip.IsMulticast()
+ }
+ }
+ return false
+}
+
+// IsUnicastIPv6 returns true if its argument is a unicast IPv6 address
+func IsUnicastIPv6(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && ip.To4() == nil {
+ return !ip.IsUnspecified() && !(ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast())
+ }
+ return false
+}
+
+// IsUnicastIPv6 returns true if its argument is a globally routable IP6 address
+func IsPublicUnicastIPv6(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil && ip.To4() == nil {
+ if t := ip.To16(); t != nil && IsGloballyRoutableIP(t) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsPublicUnicastIP returns true if its argument is a global routable IPv4 or 6
+// address.
+func IsPublicUnicastIP(a net.Addr) bool {
+ if ip := AsIP(a); ip != nil {
+ if t := ip.To4(); t != nil && IsGloballyRoutableIP(t) {
+ return true
+ }
+ if t := ip.To16(); t != nil && IsGloballyRoutableIP(t) {
+ return true
+ }
+ }
+ return false
+}
+
+func diffAB(a, b AddrList) AddrList {
+ diff := AddrList{}
+ for _, av := range a {
+ found := false
+ for _, bv := range b {
+ if av.Network() == bv.Network() &&
+ av.String() == bv.String() {
+ found = true
+ break
+ }
+ }
+ if !found {
+ diff = append(diff, av)
+ }
+ }
+ return diff
+}
+
+// FindAdded returns the set of interfaces and/or addresses that are
+// present in b, but not in a - i.e. have been added.
+func FindAdded(a, b AddrList) AddrList {
+ return diffAB(b, a)
+}
+
+// FindRemoved returns the set of interfaces and/or addresses that
+// are present in a, but not in b - i.e. have been removed.
+func FindRemoved(a, b AddrList) AddrList {
+ return diffAB(a, b)
+}
diff --git a/lib/netstate/netstate_test.go b/lib/netstate/netstate_test.go
new file mode 100644
index 0000000..262d5e5
--- /dev/null
+++ b/lib/netstate/netstate_test.go
@@ -0,0 +1,252 @@
+package netstate_test
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "reflect"
+ "testing"
+
+ "veyron/lib/netstate"
+)
+
+func TestGet(t *testing.T) {
+ all, err := netstate.GetAll()
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ accessible, err := netstate.GetAccessibleIPs()
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if len(all) == 0 || len(accessible) == 0 {
+ t.Errorf("expected non zero lengths, not %d and %d", len(all), len(accessible))
+ }
+ if len(accessible) > len(all) {
+ t.Errorf("should never be more accessible addresses than 'all' addresses")
+ }
+ loopback := netstate.FindAdded(accessible, all)
+ if got, want := loopback.Filter(netstate.IsLoopbackIP), loopback; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %v, want %v", got, want)
+ }
+}
+
+func mkAddr(n, a string) net.Addr {
+ ip := net.ParseIP(a)
+ fmt.Fprintf(os.Stderr, "%s -> %d\n", a, len(ip))
+ return netstate.AsAddr(n, ip)
+}
+
+func TestAsIP(t *testing.T) {
+ lh := net.ParseIP("127.0.0.1")
+ if got, want := netstate.AsIP(&net.IPAddr{IP: lh}), "127.0.0.1"; got == nil || got.String() != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+ if got, want := netstate.AsIP(&net.IPNet{IP: lh}), "127.0.0.1"; got == nil || got.String() != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+ if got, want := netstate.AsIP(netstate.AsAddr("tcp", lh)), "127.0.0.1"; got == nil || got.String() != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+}
+
+type hw struct{}
+
+func (*hw) Network() string { return "mac" }
+func (*hw) String() string { return "01:23:45:67:89:ab:cd:ef" }
+
+func TestPredicates(t *testing.T) {
+ if got, want := netstate.IsUnicastIP(&hw{}), false; got != want {
+ t.Errorf("got %t, want %t", got, want)
+
+ }
+
+ cases := []struct {
+ f func(a net.Addr) bool
+ a string
+ r bool
+ }{
+ {netstate.IsUnspecifiedIP, "0.0.0.0", true},
+ {netstate.IsUnspecifiedIP, "::", true},
+ {netstate.IsUnspecifiedIP, "127.0.0.1", false},
+ {netstate.IsUnspecifiedIP, "::1", false},
+
+ {netstate.IsLoopbackIP, "0.0.0.0", false},
+ {netstate.IsLoopbackIP, "::", false},
+ {netstate.IsLoopbackIP, "127.0.0.1", true},
+ {netstate.IsLoopbackIP, "::1", true},
+
+ {netstate.IsAccessibleIP, "0.0.0.0", false},
+ {netstate.IsAccessibleIP, "::", false},
+ {netstate.IsAccessibleIP, "127.0.0.1", false},
+ {netstate.IsAccessibleIP, "::1", false},
+ {netstate.IsAccessibleIP, "224.0.0.2", true},
+ {netstate.IsAccessibleIP, "fc00:1234::", true},
+ {netstate.IsAccessibleIP, "192.168.1.1", true},
+ {netstate.IsAccessibleIP, "2001:4860:0:2001::68", true},
+
+ {netstate.IsUnicastIP, "0.0.0.0", false},
+ {netstate.IsUnicastIP, "::", false},
+ {netstate.IsUnicastIP, "127.0.0.1", true},
+ {netstate.IsUnicastIP, "::1", true},
+ {netstate.IsUnicastIP, "192.168.1.2", true},
+ {netstate.IsUnicastIP, "74.125.239.36", true},
+ {netstate.IsUnicastIP, "224.0.0.2", false},
+ {netstate.IsUnicastIP, "fc00:1235::", true},
+ {netstate.IsUnicastIP, "ff01::01", false},
+ {netstate.IsUnicastIP, "2001:4860:0:2001::69", true},
+
+ {netstate.IsUnicastIPv4, "0.0.0.0", false},
+ {netstate.IsUnicastIPv4, "::", false},
+ {netstate.IsUnicastIPv4, "127.0.0.1", true},
+ {netstate.IsUnicastIPv4, "::1", false},
+ {netstate.IsUnicastIPv4, "192.168.1.3", true},
+ {netstate.IsUnicastIPv6, "74.125.239.37", false},
+ {netstate.IsUnicastIPv4, "224.0.0.2", false},
+ {netstate.IsUnicastIPv4, "fc00:1236::", false},
+ {netstate.IsUnicastIPv4, "ff01::02", false},
+ {netstate.IsUnicastIPv4, "2001:4860:0:2001::6a", false},
+
+ {netstate.IsUnicastIPv6, "0.0.0.0", false},
+ {netstate.IsUnicastIPv6, "::", false},
+ {netstate.IsUnicastIPv6, "127.0.0.1", false},
+ {netstate.IsUnicastIPv6, "::1", true},
+ {netstate.IsUnicastIPv6, "192.168.1.4", false},
+ {netstate.IsUnicastIPv6, "74.125.239.38", false},
+ {netstate.IsUnicastIPv6, "224.0.0.2", false},
+ {netstate.IsUnicastIPv6, "fc00:1237::", true},
+ {netstate.IsUnicastIPv6, "ff01::03", false},
+ {netstate.IsUnicastIPv6, "2607:f8b0:4003:c00::6b", true},
+
+ {netstate.IsPublicUnicastIP, "0.0.0.0", false},
+ {netstate.IsPublicUnicastIP, "::", false},
+ {netstate.IsPublicUnicastIP, "127.0.0.1", false},
+ {netstate.IsPublicUnicastIP, "::1", false},
+ {netstate.IsPublicUnicastIP, "192.168.1.2", false},
+ {netstate.IsPublicUnicastIP, "74.125.239.39", true},
+ {netstate.IsPublicUnicastIP, "224.0.0.2", false},
+ // Arguably this is buggy, the fc00:/7 prefix is supposed to be
+ // non-routable.
+ {netstate.IsPublicUnicastIP, "fc00:1238::", true},
+ {netstate.IsPublicUnicastIP, "ff01::01", false},
+ {netstate.IsPublicUnicastIP, "2001:4860:0:2001::69", true},
+
+ {netstate.IsPublicUnicastIPv4, "0.0.0.0", false},
+ {netstate.IsPublicUnicastIPv4, "::", false},
+ {netstate.IsPublicUnicastIPv4, "127.0.0.1", false},
+ {netstate.IsPublicUnicastIPv4, "::1", false},
+ {netstate.IsPublicUnicastIPv4, "192.168.1.3", false},
+ {netstate.IsPublicUnicastIPv4, "74.125.239.40", true},
+ {netstate.IsPublicUnicastIPv4, "224.0.0.2", false},
+ {netstate.IsPublicUnicastIPv4, "fc00:1239::", false},
+ {netstate.IsPublicUnicastIPv4, "ff01::02", false},
+ {netstate.IsPublicUnicastIPv4, "2001:4860:0:2001::6a", false},
+
+ {netstate.IsPublicUnicastIPv6, "0.0.0.0", false},
+ {netstate.IsPublicUnicastIPv6, "::", false},
+ {netstate.IsPublicUnicastIPv6, "127.0.0.1", false},
+ {netstate.IsPublicUnicastIPv6, "::1", false},
+ {netstate.IsPublicUnicastIPv6, "192.168.1.4", false},
+ {netstate.IsPublicUnicastIPv6, "74.125.239.41", false},
+ {netstate.IsPublicUnicastIPv6, "224.0.0.2", false},
+ // Arguably this is buggy, the fc00:/7 prefix is supposed to be
+ // non-routable.
+ {netstate.IsPublicUnicastIPv6, "fc00:123a::", true},
+ {netstate.IsPublicUnicastIPv6, "ff01::03", false},
+ {netstate.IsPublicUnicastIPv6, "2607:f8b0:4003:c00::6b", true},
+ }
+ for i, c := range cases {
+ net := "tcp"
+ if got, want := c.f(mkAddr(net, c.a)), c.r; got != want {
+ t.Errorf("#%d: %s %s: got %t, want %t", i+1, net, c.a, got, want)
+ }
+ }
+}
+
+var (
+ a = mkAddr("tcp4", "1.2.3.4")
+ b = mkAddr("tcp4", "1.2.3.5")
+ c = mkAddr("tcp4", "1.2.3.6")
+ d = mkAddr("tcp4", "1.2.3.7")
+ a6 = mkAddr("tcp6", "2001:4860:0:2001::68")
+ b6 = mkAddr("tcp6", "2001:4860:0:2001::69")
+ c6 = mkAddr("tcp6", "2001:4860:0:2001::70")
+ d6 = mkAddr("tcp6", "2001:4860:0:2001::71")
+)
+
+func TestRemoved(t *testing.T) {
+ al := netstate.AddrList{a, b, c, a6, b6, c6}
+ bl := netstate.AddrList{}
+
+ // no changes.
+ got, want := netstate.FindRemoved(al, al), netstate.AddrList{}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got %#v, want %#v", got, want)
+ }
+
+ // missing everything
+ if got, want := netstate.FindRemoved(al, bl), al; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // missing nothing
+ if got, want := netstate.FindRemoved(bl, al), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // remove some addresses
+ bl = netstate.AddrList{a, b, a6, b6}
+ if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{c, c6}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // add some addresses
+ bl = netstate.AddrList{a, b, c, a6, b6, c6, d6}
+ if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // change some addresses
+ bl = netstate.AddrList{a, b, d, a6, d6, c6}
+ if got, want := netstate.FindRemoved(al, bl), (netstate.AddrList{c, b6}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+}
+
+func TestAdded(t *testing.T) {
+ al := netstate.AddrList{a, b, c, a6, b6, c6}
+ bl := netstate.AddrList{}
+
+ // no changes.
+ if got, want := netstate.FindAdded(al, al), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // add nothing
+ if got, want := netstate.FindAdded(al, bl), bl; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // add everything
+ if got, want := netstate.FindAdded(bl, al), al; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // add some addresses
+ bl = netstate.AddrList{a, b, c, d, a6, b6, c6, d6}
+ if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{d, d6}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // remove some addresses
+ bl = netstate.AddrList{a, b, c, b6}
+ if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+
+ // change some addresses
+ bl = netstate.AddrList{a, d, c, a6, d6, c6}
+ if got, want := netstate.FindAdded(al, bl), (netstate.AddrList{d, d6}); !reflect.DeepEqual(got, want) {
+ t.Errorf("got %s, want %s", got, want)
+ }
+}
diff --git a/profiles/net/init.go b/profiles/net/init.go
index e38a6f5..6f61d3e 100644
--- a/profiles/net/init.go
+++ b/profiles/net/init.go
@@ -20,10 +20,8 @@
"veyron2/config"
"veyron2/rt"
+ "veyron/lib/netconfig"
"veyron/profiles"
-
- // TODO(cnicolaou): move this to profiles/internal
- "veyron/runtimes/google/lib/netconfig"
)
const (
diff --git a/profiles/net/util.go b/profiles/net/util.go
index 721ed29..57d42a5 100644
--- a/profiles/net/util.go
+++ b/profiles/net/util.go
@@ -4,10 +4,12 @@
"fmt"
"net"
- // TODO(cnicolaou): move this out of the runtimes and into here.
- "veyron/runtimes/google/lib/netconfig"
+ "veyron/lib/netstate"
)
+// TODO(cnicolaou): this will be removed in a subsequent CL by using the
+// new netstate library.
+
// ipAndIf is a map of interface name to the set of IP addresses available on
// that interface.
type ipAndIf map[string][]net.IP
@@ -112,7 +114,7 @@
if ip == nil {
return false
}
- return netconfig.IsGloballyRoutable(ip)
+ return netstate.IsGloballyRoutableIP(ip)
}
func diffAB(a, b ipAndIf) ipAndIf {
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 3135149..54a3193 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -1110,7 +1110,7 @@
sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
defer sm.Shutdown()
ns := newNamespace()
- pa := func(string) (net.Addr, error) {
+ pa := func(string, []net.Addr) (net.Addr, error) {
a := &net.IPAddr{}
a.IP = net.ParseIP("1.1.1.1")
return a, nil
@@ -1145,7 +1145,7 @@
sm := imanager.InternalNew(naming.FixedRoutingID(0x555555555))
defer sm.Shutdown()
ns := newNamespace()
- paerr := func(string) (net.Addr, error) {
+ paerr := func(string, []net.Addr) (net.Addr, error) {
return nil, fmt.Errorf("oops")
}
server, err := InternalNewServer(testContext(), sm, ns, vc.FixedLocalID(serverID), veyron2.PreferredAddressOpt(paerr))
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 5b5b36d..a51942c 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -9,7 +9,8 @@
"sync"
"time"
- "veyron/runtimes/google/lib/netconfig"
+ "veyron/lib/netstate"
+
"veyron/runtimes/google/lib/publisher"
inaming "veyron/runtimes/google/naming"
isecurity "veyron/runtimes/google/security"
@@ -46,7 +47,7 @@
stopped bool // whether the server has been stopped.
stoppedChan chan struct{} // closed when the server has been stopped.
ns naming.Namespace
- preferredAddress func(network string) (net.Addr, error)
+ preferredAddress func(network string, addrs []net.Addr) (net.Addr, error)
servesMountTable bool
}
@@ -113,57 +114,16 @@
// preferredIPAddress returns the preferred IP address, which is,
// a public IPv4 address, then any non-loopback IPv4, then a public
// IPv6 address and finally any non-loopback/link-local IPv6
-func preferredIPAddress(network string) (net.Addr, error) {
- interfaces, err := net.Interfaces()
- if err != nil {
- return nil, err
+func preferredIPAddress(network string, addrs []net.Addr) (net.Addr, error) {
+ if !netstate.IsIPNetwork(network) {
+ return nil, fmt.Errorf("can't support network %q", network)
}
- var any_ip4, any_ip6, pub_ip4, pub_ip6 net.Addr
- for _, ifc := range interfaces {
- addrs, err := ifc.Addrs()
- if err != nil {
- continue
+ al := netstate.AddrList(addrs)
+ for _, predicate := range []netstate.Predicate{netstate.IsPublicUnicastIPv4,
+ netstate.IsUnicastIPv4, netstate.IsPublicUnicastIPv6} {
+ if a := al.First(predicate); a != nil {
+ return a, nil
}
- for _, addr := range addrs {
- ipn, ok := addr.(*net.IPNet)
- if !ok {
- continue
- }
- ip := ipn.IP
- if ip == nil || ip.IsUnspecified() || ip.IsLoopback() || ip.IsMulticast() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
- continue
- }
- if network == "tcp" || network == "tcp4" {
- if t := ip.To4(); t != nil {
- if any_ip4 == nil {
- any_ip4 = addr
- }
- if pub_ip4 == nil && netconfig.IsGloballyRoutable(t) {
- pub_ip4 = addr
- }
- }
- }
- if network == "tcp" || network == "tcp6" {
- if t := ip.To16(); t != nil {
- if any_ip6 == nil {
- any_ip6 = addr
- }
- if pub_ip6 == nil && netconfig.IsGloballyRoutable(t) {
- pub_ip6 = addr
- }
- }
- }
- }
- }
- switch {
- case pub_ip4 != nil:
- return pub_ip4, nil
- case any_ip4 != nil:
- return any_ip4, nil
- case pub_ip6 != nil:
- return pub_ip6, nil
- case any_ip6 != nil:
- return any_ip6, nil
}
return nil, fmt.Errorf("failed to find any usable address for %q", network)
}
@@ -208,8 +168,11 @@
}
if ip.IsUnspecified() && s.preferredAddress != nil {
// Need to find a usable IP address.
- if a, err := s.preferredAddress(protocol); err == nil {
- iep.Address = net.JoinHostPort(a.String(), port)
+ addrs, err := netstate.GetAccessibleIPs()
+ if err == nil {
+ if a, err := s.preferredAddress(protocol, addrs); err == nil {
+ iep.Address = net.JoinHostPort(a.String(), port)
+ }
}
}
}
diff --git a/services/mounttable/lib/neighborhood.go b/services/mounttable/lib/neighborhood.go
index 738c058..1fc8089 100644
--- a/services/mounttable/lib/neighborhood.go
+++ b/services/mounttable/lib/neighborhood.go
@@ -7,7 +7,7 @@
"strings"
"veyron/lib/glob"
- "veyron/runtimes/google/lib/netconfig"
+ "veyron/lib/netconfig"
"veyron2/ipc"
"veyron2/naming"