Revert "[netstack] Route table re-architecture"
This reverts commit 52059d0841223d5c3001d1204d37e511f747cb28.
Reason for revert: breaks global integration
Original change's description:
> [netstack] Route table re-architecture
>
> Note: Part of the code implements a soft transition in the netstack.fidl to
> avoid breaking Chromium. The soft transition copies and extends the
> NetInterface and RouteTableEntry structs as well as the functions using them.
> Once Chromium transitions away from netstack.fidl this can be removed.
>
> The main change cleans up and improves the route table logic by doing several
> things:
>
> 1)
> The per-interface route tables stored in netiface.NIC are removed and
> consolidated in its own route_table package and RouteTable type.
>
> 2)
> The fuchsia.netstack.fidl RouteTableTransaction interface is simplified by
> replacing the current {Get,Set}RouteTable and Commit functions with simpler
> {Add,Del}Route ones. This also matches the {Add,Del}ForwardingEntry APIs in the
> new fuchsia.net.stack nicely.
>
> 3)
>
> The RouteTable type implements a sorted table of routes that carry additional
> attributes besides the standard tcpip.Route, most importantly a metric value
> that is used as a tie-breaker when sorting the table. The metric can either be
> statically chosen by the user, or dynamically chosen by tracking the metric of
> the interface the route points to. An according metric value is added to the
> netiface.NIC struct, which can be overwritten via ifconfig command. This allows
> to favor defaults routes going out a specific interface. E.g., if both WLAN and
> Ethernet ports have obtained IP addresses and gateways via DHCP, setting a
> lower metric on the WLAN interface can favor it over the Ethernet one so its
> default route is sorted above the Ethernet's.
>
> In addition, static IPs assigned to an interface as well as their subnet routes
> are not removed anymore when the interface goes down. Rather, Netstack
> remembers whether the address was obtained dynamically (DHCP) or statically and
> only removes the dynamic one. Static IPs remain assigned, but its subnet route
> disabled via an extended route attribute, so it isn't used by gVisor Netstack.
> Eventually, this behavior should be coming from netcfg.
>
> NET-1773 #done
> NET-1916 #done
> NET-2054 #done
> NET-1978
> NET-1223
>
> Tested:
> - Unit-tests: fx run-test netstack_gotests
>
> - Manual tests on device:
> Plug eth04p into MacBook, configure static IP on MacBook:
> sudo ifconfig en8 inet 192.168.10.2 netmask 255.255.255.0
>
> On Toulouse:
> fx shell ifconfig ethp04 up
> fx shell ifconfig ethp04
> (should be UP, metric 100)
>
> fx shell ifconfig ethp04 add 192.168.10.3/24 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (verify new IP is set, and new "192.168.10.0/24 via ethp04 metric 100" route entry in the proper place)
>
> ping 192.168.10.2
> (pinging MacBook succeeds, same goes for the other direction pinging
> 192.168.10.3 from MacBook)
>
> fx shell ifconfig ethp04 down && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (IP address and route remain, but are disabled)
>
> ping 192.168.10.2
> (Pinging either direction doesn't work)
>
> fx shell ifconfig ethp04 up && fx shell ifconfig ethp04 up && \
> fx shell ifconfig ethp04 && fx shell ifconfig route show
> (IP and route still there, re-enabled)
>
> ping 192.168.10.2
> (pinging works again in both directions)
>
> fx shell ifconfig ethp04 metric 50 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (if and route metric changed to 50, route moved up one spot)
>
> fx shell ifconfig route add 192.168.20.0/24 iface ethp04 && \
> fx shell ifconfig ethp04 && fx shell ifconfig route show
> (Route is added to the table, no gateway, metric is 50 from ethp04)
>
> fx shell ifconfig route add 192.168.30.0/24 iface ethp04 gateway \
> 192.168.30.1 metric 150 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (Route is added, with gateway, metric is 150, not tracking ethp04, sorted
> below the other routes on ethp04 due to higher metric)
>
> fx shell ifconfig route add 0.0.0.0/0 iface ethp04 gateway 192.168.30.1 \
> metric 110 && fx shell ifconfig ethp04 && fx shell ifconfig route show
> (Default is added, with gateway 192.168.30.1, metric 110 not tracking
> ethp04, sorted below other default routes due to higher metric)
>
> fx shell ifconfig ethp04 metric 200 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (all routes tracking ethp04's are updated to metric=200 and the table is
> resorted)
>
> fx shell ifconfig route del 0.0.0.0/0 iface ethp04 && \
> fx shell ifconfig ethp04 && fx shell ifconfig route show
> (Removes default route on ethp04)
>
> fx shell ifconfig route del 192.168.30.0/24 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
>
> fx shell ifconfig route del 192.168.20.0/24 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (Removes 192.168.{30,20}/24 routes)
>
> fx shell ifconfig ethp04 del 192.168.10.3/24 && fx shell ifconfig ethp04 && \
> fx shell ifconfig route show
> (IP and route are removed)
>
> Change-Id: Id6b4232986493ec313d29d4f236461c491eeda2e
TBR=stijlist@google.com,tamird@google.com,eyalsoha@google.com,brunodalbo@google.com,ckuiper@google.com
Change-Id: I70843342680d315447b29db62de4b83f6bb7754c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
diff --git a/garnet/bin/guest/integration/mock_netstack.h b/garnet/bin/guest/integration/mock_netstack.h
index 3d7a448..dd9ac82 100644
--- a/garnet/bin/guest/integration/mock_netstack.h
+++ b/garnet/bin/guest/integration/mock_netstack.h
@@ -21,10 +21,8 @@
GetAddressCallback callback) override {}
void GetInterfaces(GetInterfacesCallback callback) override {}
- void GetInterfaces2(GetInterfaces2Callback callback) override {}
void GetRouteTable(GetRouteTableCallback callback) override {}
- void GetRouteTable2(GetRouteTable2Callback callback) override {}
void GetStats(uint32_t nicid, GetStatsCallback callback) override {}
@@ -40,9 +38,6 @@
uint32_t nicid, fuchsia::net::IpAddress addr, uint8_t prefixLen,
RemoveInterfaceAddressCallback callback) override {}
- void SetInterfaceMetric(uint32_t nicid, uint32_t metric,
- SetInterfaceMetricCallback callback) override {}
-
void SetDhcpClientStatus(uint32_t nicid, bool enabled,
SetDhcpClientStatusCallback callback) override {}
@@ -79,4 +74,4 @@
uintptr_t io_addr_;
};
-#endif // GARNET_BIN_GUEST_INTEGRATION_MOCK_NETSTACK_H_
+#endif // GARNET_BIN_GUEST_INTEGRATION_MOCK_NETSTACK_H_
\ No newline at end of file
diff --git a/garnet/bin/guest/vmm/device/virtio_net_test.cc b/garnet/bin/guest/vmm/device/virtio_net_test.cc
index 8f628d5..792302be 100644
--- a/garnet/bin/guest/vmm/device/virtio_net_test.cc
+++ b/garnet/bin/guest/vmm/device/virtio_net_test.cc
@@ -30,10 +30,8 @@
GetAddressCallback callback) override {}
void GetInterfaces(GetInterfacesCallback callback) override {}
- void GetInterfaces2(GetInterfaces2Callback callback) override {}
void GetRouteTable(GetRouteTableCallback callback) override {}
- void GetRouteTable2(GetRouteTable2Callback callback) override {}
void GetStats(uint32_t nicid, GetStatsCallback callback) override {}
@@ -49,9 +47,6 @@
uint32_t nicid, fuchsia::net::IpAddress addr, uint8_t prefixLen,
RemoveInterfaceAddressCallback callback) override {}
- void SetInterfaceMetric(uint32_t nicid, uint32_t metric,
- SetInterfaceMetricCallback callback) override {}
-
void SetDhcpClientStatus(uint32_t nicid, bool enabled,
SetDhcpClientStatusCallback callback) override {}
diff --git a/garnet/bin/netcfg/src/main.rs b/garnet/bin/netcfg/src/main.rs
index ea86ad1..70ddf2b 100644
--- a/garnet/bin/netcfg/src/main.rs
+++ b/garnet/bin/netcfg/src/main.rs
@@ -54,7 +54,7 @@
}
}
-fn derive_device_name(interfaces: Vec<fidl_fuchsia_netstack::NetInterface2>) -> Option<String> {
+fn derive_device_name(interfaces: Vec<fidl_fuchsia_netstack::NetInterface>) -> Option<String> {
interfaces
.iter()
.filter(|iface| {
@@ -102,12 +102,9 @@
let mut device_name_stream = futures::stream::iter(default_device_name).chain(
netstack.take_event_stream().try_filter_map(
- |event| match event {
- fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged2 { interfaces } => {
- futures::future::ok(derive_device_name(interfaces).map(Cow::Owned))
- },
- _ => futures::future::ok(None),
- }
+ |fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged { interfaces }| {
+ futures::future::ok(derive_device_name(interfaces).map(Cow::Owned))
+ },
),
);
diff --git a/garnet/bin/netemul_runner/helpers/netstack_cfg/src/main.rs b/garnet/bin/netemul_runner/helpers/netstack_cfg/src/main.rs
index e926639..751b15e 100644
--- a/garnet/bin/netemul_runner/helpers/netstack_cfg/src/main.rs
+++ b/garnet/bin/netemul_runner/helpers/netstack_cfg/src/main.rs
@@ -64,19 +64,13 @@
};
let mut if_changed = netstack.take_event_stream().try_filter_map(
- |event| match event {
- fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged2 { interfaces } => {
- let iface = interfaces
- .iter()
- .filter(|iface| iface.name == if_name)
- .next();
- match iface {
- None => futures::future::ok(None),
- Some(a) => futures::future::ok(Some((a.id, a.hwaddr.clone()))),
- }
- },
- _ => futures::future::ok(None),
- }
+ |fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged { interfaces }| {
+ let iface = interfaces.iter().filter(|iface| iface.name == if_name).next();
+ match iface {
+ None => futures::future::ok(None),
+ Some(a) => futures::future::ok(Some((a.id, a.hwaddr.clone()))),
+ }
+ },
);
let _nicid =
await!(netstack.add_ethernet_device(&format!("/vdev/{}", opt.endpoint), &mut cfg, eth))
diff --git a/garnet/bin/netemul_runner/test/netstack_socks/src/child.rs b/garnet/bin/netemul_runner/test/netstack_socks/src/child.rs
index 81f21fe..e394afa 100644
--- a/garnet/bin/netemul_runner/test/netstack_socks/src/child.rs
+++ b/garnet/bin/netemul_runner/test/netstack_socks/src/child.rs
@@ -100,19 +100,13 @@
};
let mut if_changed = netstack.take_event_stream().try_filter_map(
- |event| match event {
- fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged2 { interfaces } => {
- let iface = interfaces
- .iter()
- .filter(|iface| iface.name == if_name)
- .next();
- match iface {
- None => futures::future::ok(None),
- Some(a) => futures::future::ok(Some((a.id, a.hwaddr.clone()))),
- }
- },
- _ => futures::future::ok(None),
- }
+ |fidl_fuchsia_netstack::NetstackEvent::OnInterfacesChanged { interfaces }| {
+ let iface = interfaces.iter().filter(|iface| iface.name == if_name).next();
+ match iface {
+ None => futures::future::ok(None),
+ Some(a) => futures::future::ok(Some((a.id, a.hwaddr.clone()))),
+ }
+ },
);
let _nicid =
await!(netstack.add_ethernet_device(&format!("/vdev/{}", opt.endpoint), &mut cfg, eth))
diff --git a/garnet/go/src/netstack/BUILD.gn b/garnet/go/src/netstack/BUILD.gn
index 2b31482..abe34c5 100644
--- a/garnet/go/src/netstack/BUILD.gn
+++ b/garnet/go/src/netstack/BUILD.gn
@@ -61,6 +61,7 @@
":netstack_fidlconv_test",
":netstack_filter_test",
":netstack_link_eth_test",
+ ":netstack_netiface_test",
":netstack_test",
"netstack_service_test",
"//garnet/go/src/netstack/util:netstack_util_test",
@@ -86,6 +87,9 @@
name = "netstack_link_eth_test"
},
{
+ name = "netstack_netiface_test"
+ },
+ {
name = "netstack_test"
},
{
@@ -161,6 +165,13 @@
]
}
+go_test("netstack_netiface_test") {
+ gopackage = "netstack/netiface"
+ deps = [
+ ":netstack_lib",
+ ]
+}
+
go_test("netstack_test") {
gopackage = "netstack"
deps = [
diff --git a/garnet/go/src/netstack/connectivity/connectivity.go b/garnet/go/src/netstack/connectivity/connectivity.go
index 6180137..cc00e60 100644
--- a/garnet/go/src/netstack/connectivity/connectivity.go
+++ b/garnet/go/src/netstack/connectivity/connectivity.go
@@ -11,7 +11,7 @@
"app/context"
"netstack/fidlconv"
- "netstack/util"
+ "netstack/netiface"
"fidl/fuchsia/net"
"fidl/fuchsia/netstack"
@@ -37,7 +37,7 @@
// TODO(NET-1001): extract into a separate reachability service based on a
// better network reachability signal.
-func InferAndNotify(ifs []netstack.NetInterface2) {
+func InferAndNotify(ifs []netstack.NetInterface) {
if debug {
log.Printf("inferring network reachability")
}
@@ -53,11 +53,11 @@
mu.Unlock()
}
-func hasDHCPAddress(nic netstack.NetInterface2) bool {
- return nic.Flags&netstack.NetInterfaceFlagDhcp != 0 && nic.Flags&netstack.NetInterfaceFlagUp != 0 && !util.IsAny(fidlconv.ToTCPIPAddress(nic.Addr))
+func hasDHCPAddress(nic netstack.NetInterface) bool {
+ return nic.Flags&netstack.NetInterfaceFlagDhcp != 0 && nic.Flags&netstack.NetInterfaceFlagUp != 0 && !netiface.IsAny(fidlconv.ToTCPIPAddress(nic.Addr))
}
-func inferReachability(ifs []netstack.NetInterface2) bool {
+func inferReachability(ifs []netstack.NetInterface) bool {
for _, nic := range ifs {
if hasDHCPAddress(nic) {
return true
diff --git a/garnet/go/src/netstack/connectivity/connectivity_test.go b/garnet/go/src/netstack/connectivity/connectivity_test.go
index 368c246..3959ee5 100644
--- a/garnet/go/src/netstack/connectivity/connectivity_test.go
+++ b/garnet/go/src/netstack/connectivity/connectivity_test.go
@@ -23,12 +23,12 @@
func TestHasDHCPAddress(t *testing.T) {
for _, tc := range []struct {
name string
- iface netstack.NetInterface2
+ iface netstack.NetInterface
want bool
}{
{
name: "DHCPEnabledNoAddress",
- iface: netstack.NetInterface2{
+ iface: netstack.NetInterface{
Flags: netstack.NetInterfaceFlagDhcp | netstack.NetInterfaceFlagUp,
Addr: newV4Address(0, 0, 0, 0),
Netmask: newV4Address(0, 0, 0, 0),
@@ -39,7 +39,7 @@
},
{
name: "StaticAddress",
- iface: netstack.NetInterface2{
+ iface: netstack.NetInterface{
Flags: netstack.NetInterfaceFlagUp,
Addr: newV4Address(192, 168, 42, 10),
Netmask: newV4Address(255, 255, 255, 0),
@@ -50,7 +50,7 @@
},
{
name: "DHCPEnabledWithAddress",
- iface: netstack.NetInterface2{
+ iface: netstack.NetInterface{
Flags: netstack.NetInterfaceFlagDhcp | netstack.NetInterfaceFlagUp,
Addr: newV4Address(10, 0, 0, 1),
Netmask: newV4Address(255, 255, 255, 0),
diff --git a/garnet/go/src/netstack/ifconfig/ifconfig.go b/garnet/go/src/netstack/ifconfig/ifconfig.go
index c0226450..6287aa2 100644
--- a/garnet/go/src/netstack/ifconfig/ifconfig.go
+++ b/garnet/go/src/netstack/ifconfig/ifconfig.go
@@ -8,7 +8,6 @@
"fmt"
"net"
"os"
- "strconv"
"strings"
"syscall/zx"
@@ -30,7 +29,7 @@
}
func (a *netstackClientApp) printAll() {
- ifaces, err := a.netstack.GetInterfaces2()
+ ifaces, err := a.netstack.GetInterfaces()
if err != nil {
fmt.Print("ifconfig: failed to fetch interfaces\n")
return
@@ -41,8 +40,8 @@
}
}
-func getIfaceByNameFromIfaces(name string, ifaces []netstack.NetInterface2) *netstack.NetInterface2 {
- var candidate *netstack.NetInterface2
+func getIfaceByNameFromIfaces(name string, ifaces []netstack.NetInterface) *netstack.NetInterface {
+ var candidate *netstack.NetInterface
for i, iface := range ifaces {
if strings.HasPrefix(iface.Name, name) {
if candidate != nil {
@@ -54,7 +53,7 @@
return candidate
}
-func getIfaceByIdFromIfaces(id uint32, ifaces []netstack.NetInterface2) *netstack.NetInterface2 {
+func getIfaceByIdFromIfaces(id uint32, ifaces []netstack.NetInterface) *netstack.NetInterface {
for _, iface := range ifaces {
if iface.Id == id {
return &iface
@@ -63,7 +62,7 @@
return nil
}
-func (a *netstackClientApp) printIface(iface netstack.NetInterface2) {
+func (a *netstackClientApp) printIface(iface netstack.NetInterface) {
stats, err := a.netstack.GetStats(iface.Id)
if err != nil {
@@ -77,7 +76,6 @@
// TODO: scopes
fmt.Printf("\tinet6 addr: %s/%d Scope:Link\n", netAddrToString(addr.Addr), addr.PrefixLen)
}
- fmt.Printf("\tmetric:%d\n", iface.Metric)
fmt.Printf("\t%s\n", flagsToString(iface.Flags))
if isWLAN(iface.Features) {
@@ -92,11 +90,11 @@
// TODO: more stats. MTU, RX/TX errors
}
-func (a *netstackClientApp) setStatus(iface netstack.NetInterface2, up bool) {
+func (a *netstackClientApp) setStatus(iface netstack.NetInterface, up bool) {
a.netstack.SetInterfaceStatus(iface.Id, up)
}
-func (a *netstackClientApp) addIfaceAddress(iface netstack.NetInterface2, cidr string) {
+func (a *netstackClientApp) addIfaceAddress(iface netstack.NetInterface, cidr string) {
netAddr, prefixLen := validateCidr(os.Args[3])
result, _ := a.netstack.SetInterfaceAddress(iface.Id, netAddr, prefixLen)
if result.Status != netstack.StatusOk {
@@ -104,7 +102,7 @@
}
}
-func (a *netstackClientApp) removeIfaceAddress(iface netstack.NetInterface2, cidr string) {
+func (a *netstackClientApp) removeIfaceAddress(iface netstack.NetInterface, cidr string) {
netAddr, prefixLen := validateCidr(os.Args[3])
result, _ := a.netstack.RemoveInterfaceAddress(iface.Id, netAddr, prefixLen)
if result.Status != netstack.StatusOk {
@@ -112,23 +110,16 @@
}
}
-func (a *netstackClientApp) parseRouteAttribute(in *netstack.RouteTableEntry2, args []string) (remaining []string, err error) {
+func (a *netstackClientApp) parseRouteAttribute(in *netstack.RouteTableEntry, args []string) (remaining []string, err error) {
if len(args) < 2 {
return args, fmt.Errorf("not enough args to make attribute")
}
var attr, val string
switch attr, val, remaining = args[0], args[1], args[2:]; attr {
case "gateway":
- gateway := toIpAddress(net.ParseIP(val))
- in.Gateway = &gateway
- case "metric":
- m, err := strconv.ParseUint(val, 10, 32)
- if err != nil {
- return remaining, fmt.Errorf("metric value '%s' is not uint32: %s", val, err)
- }
- in.Metric = uint32(m)
+ in.Gateway = toIpAddress(net.ParseIP(val))
case "iface":
- ifaces, err := a.netstack.GetInterfaces2()
+ ifaces, err := a.netstack.GetInterfaces()
if err != nil {
return remaining, err
}
@@ -148,7 +139,7 @@
return remaining, nil
}
-func (a *netstackClientApp) newRouteFromArgs(args []string) (route netstack.RouteTableEntry2, err error) {
+func (a *netstackClientApp) newRouteFromArgs(args []string) (route netstack.RouteTableEntry, err error) {
destination, remaining := args[0], args[1:]
dstAddr, dstSubnet, err := net.ParseCIDR(destination)
if err != nil {
@@ -172,11 +163,10 @@
return route, nil
}
-func (a *netstackClientApp) addRoute(r netstack.RouteTableEntry2) error {
- if r.Gateway == nil && r.Nicid == 0 {
+func (a *netstackClientApp) addRoute(r netstack.RouteTableEntry) error {
+ if (r.Gateway == netfidl.IpAddress{}) && r.Nicid == 0 {
return fmt.Errorf("either gateway or iface must be provided when adding a route")
}
-
req, transactionInterface, err := netstack.NewRouteTableTransactionInterfaceRequest()
if err != nil {
return fmt.Errorf("could not make a new route table transaction: %s", err)
@@ -186,18 +176,58 @@
if err != nil || zx.Status(status) != zx.ErrOk {
return fmt.Errorf("could not start a route table transaction: %s (%s)", err, zx.Status(status))
}
-
- status, err = transactionInterface.AddRoute(r)
+ rs, err := transactionInterface.GetRouteTable()
if err != nil {
- return fmt.Errorf("could not add route due to transaction interface error: %s", err)
+ return fmt.Errorf("could not get route table from netstack: %s", err)
}
- if zx.Status(status) != zx.ErrOk {
- return fmt.Errorf("could not add route in netstack: %s", zx.Status(status))
+ err = transactionInterface.SetRouteTable(append(rs, r))
+ if err != nil {
+ return fmt.Errorf("could not set route table in netstack: %s", err)
+ }
+ status, err = transactionInterface.Commit()
+ if err != nil || zx.Status(status) != zx.ErrOk {
+ return fmt.Errorf("could not commit route table in netstack: %s (%s)", err, zx.Status(status))
}
return nil
}
-func (a *netstackClientApp) deleteRoute(r netstack.RouteTableEntry2) error {
+func equalIpAddress(a netfidl.IpAddress, b netfidl.IpAddress) bool {
+ if a.Which() != b.Which() {
+ return false
+ }
+ switch a.Which() {
+ case netfidl.IpAddressIpv4:
+ return a.Ipv4.Addr == b.Ipv4.Addr
+ case netfidl.IpAddressIpv6:
+ return a.Ipv6.Addr == b.Ipv6.Addr
+ default:
+ return false
+ }
+}
+
+// Returns true if the target matches the source. If the target is
+// missing the gateway or nicid then those are considered to be
+// matching.
+func matchRoute(target netstack.RouteTableEntry, source netstack.RouteTableEntry) bool {
+ if !equalIpAddress(target.Destination, source.Destination) {
+ return false
+ }
+ if !equalIpAddress(target.Netmask, source.Netmask) {
+ return false
+ }
+ if target.Gateway.Which() != 0 &&
+ !equalIpAddress(source.Gateway, target.Gateway) {
+ // The gateway is neither wildcard nor a match.
+ return false
+ }
+ if target.Nicid != 0 && source.Nicid != target.Nicid {
+ // The Nicid is neither wildcard nor a match.
+ return false
+ }
+ return true
+}
+
+func (a *netstackClientApp) deleteRoute(target netstack.RouteTableEntry) error {
req, transactionInterface, err := netstack.NewRouteTableTransactionInterfaceRequest()
if err != nil {
return fmt.Errorf("could not make a new route table transaction: %s", err)
@@ -208,17 +238,24 @@
return fmt.Errorf("could not start a route table transaction (maybe the route table is locked?): %s", err)
}
- status, err = transactionInterface.DelRoute(r)
+ rs, err := transactionInterface.GetRouteTable()
if err != nil {
- return fmt.Errorf("could not delete route due to transaction interface error: %s", err)
+ return fmt.Errorf("could not get route table from netstack: %s", err)
}
- if zx.Status(status) != zx.ErrOk {
- return fmt.Errorf("could not delete route in netstack: %s", zx.Status(status))
+ for i, r := range rs {
+ if matchRoute(target, r) {
+ transactionInterface.SetRouteTable(append(rs[:i], rs[i+1:]...))
+ _, err = transactionInterface.Commit()
+ if err != nil {
+ return fmt.Errorf("could not commit route table in netstack: %s", err)
+ }
+ return nil
+ }
}
- return nil
+ return fmt.Errorf("could not find route to delete in route table")
}
-func routeTableEntryToString(r netstack.RouteTableEntry2, ifaces []netstack.NetInterface2) string {
+func routeTableEntryToString(r netstack.RouteTableEntry, ifaces []netstack.NetInterface) string {
iface := getIfaceByIdFromIfaces(r.Nicid, ifaces)
var ifaceName string
if iface == nil {
@@ -233,18 +270,15 @@
case netfidl.IpAddressIpv6:
netAndMask = net.IPNet{IP: r.Destination.Ipv6.Addr[:], Mask: r.Netmask.Ipv6.Addr[:]}
}
- if r.Gateway != nil {
- return fmt.Sprintf("%s via %s %s metric %v", netAndMask.String(), netAddrToString(*r.Gateway), ifaceName, r.Metric)
- }
- return fmt.Sprintf("%s via %s metric %v", netAndMask.String(), ifaceName, r.Metric)
+ return fmt.Sprintf("%s via %s %s", netAndMask.String(), netAddrToString(r.Gateway), ifaceName)
}
func (a *netstackClientApp) showRoutes() error {
- rs, err := a.netstack.GetRouteTable2()
+ rs, err := a.netstack.GetRouteTable()
if err != nil {
return fmt.Errorf("Could not get route table from netstack: %s", err)
}
- ifaces, err := a.netstack.GetInterfaces2()
+ ifaces, err := a.netstack.GetInterfaces()
if err != nil {
return err
}
@@ -255,10 +289,10 @@
}
func (a *netstackClientApp) bridge(ifNames []string) error {
- ifs := make([]*netstack.NetInterface2, len(ifNames))
+ ifs := make([]*netstack.NetInterface, len(ifNames))
nicIDs := make([]uint32, len(ifNames))
// first, validate that all interfaces exist
- ifaces, err := a.netstack.GetInterfaces2()
+ ifaces, err := a.netstack.GetInterfaces()
if err != nil {
return err
}
@@ -279,7 +313,7 @@
return nil
}
-func (a *netstackClientApp) setDHCP(iface netstack.NetInterface2, startStop string) {
+func (a *netstackClientApp) setDHCP(iface netstack.NetInterface, startStop string) {
switch startStop {
case "start":
a.netstack.SetDhcpClientStatus(iface.Id, true)
@@ -411,11 +445,10 @@
func usage() {
fmt.Printf("Usage:\n")
fmt.Printf(" %s [<interface>]\n", os.Args[0])
- fmt.Printf(" %s <interface> {up|down}\n", os.Args[0])
- fmt.Printf(" %s <interface> {add|del} <address>/<mask>\n", os.Args[0])
- fmt.Printf(" %s <interface> metric <metric>\n", os.Args[0])
- fmt.Printf(" %s <interface> dhcp {start|stop}\n", os.Args[0])
- fmt.Printf(" %s route {add|del} <address>/<mask> [iface <name>] [gateway <address>] [metric <metric>]\n", os.Args[0])
+ fmt.Printf(" %s [<interface>] [up|down]\n", os.Args[0])
+ fmt.Printf(" %s [<interface>] [add|del] [<address>]/[<mask>]\n", os.Args[0])
+ fmt.Printf(" %s [<interface>] dhcp [start|stop]\n", os.Args[0])
+ fmt.Printf(" %s route [add|del] [<address>/<mask>] [iface <name>] [gateway <address>/<mask>]\n", os.Args[0])
fmt.Printf(" %s route show\n", os.Args[0])
fmt.Printf(" %s bridge [<interface>]+\n", os.Args[0])
os.Exit(1)
@@ -443,7 +476,7 @@
return
}
- var iface *netstack.NetInterface2
+ var iface *netstack.NetInterface
switch os.Args[1] {
case "route":
if len(os.Args) == 2 {
@@ -472,17 +505,17 @@
switch op {
case "add":
if err = a.addRoute(r); err != nil {
- fmt.Printf("Error adding route to route table: %s\n", err)
+ fmt.Printf("Error adding route to route table: %s", err)
usage()
}
case "del":
err = a.deleteRoute(r)
if err != nil {
- fmt.Printf("Error deleting route from route table: %s\n", err)
+ fmt.Printf("Error deleting route from route table: %s", err)
usage()
}
default:
- fmt.Printf("Unknown route operation: %s\n", op)
+ fmt.Printf("Unknown route operation: %s", op)
usage()
}
@@ -491,7 +524,7 @@
ifaces := os.Args[2:]
err := a.bridge(ifaces)
if err != nil {
- fmt.Printf("error creating bridge: %s\n", err)
+ fmt.Printf("error creating bridge: %s", err)
} else {
fmt.Printf("Bridged interfaces %s\n", ifaces)
}
@@ -500,7 +533,7 @@
usage()
return
default:
- ifaces, err := a.netstack.GetInterfaces2()
+ ifaces, err := a.netstack.GetInterfaces()
if err != nil {
fmt.Printf("Error finding interface name: %s\n", err)
return
@@ -519,30 +552,18 @@
switch len(os.Args) {
case 2:
a.printIface(*iface)
- case 3:
+ case 3, 4:
switch os.Args[2] {
case "up":
a.setStatus(*iface, true)
case "down":
a.setStatus(*iface, false)
- default:
- usage()
- }
- case 4:
- switch os.Args[2] {
case "add":
a.addIfaceAddress(*iface, os.Args[3])
case "del":
a.removeIfaceAddress(*iface, os.Args[3])
case "dhcp":
a.setDHCP(*iface, os.Args[3])
- case "metric":
- metric, err := strconv.ParseUint(os.Args[3], 10, 32)
- if err != nil {
- fmt.Printf("ifconfig: metric value '%s' is not uint32: %s\n", os.Args[3], err)
- return
- }
- a.netstack.SetInterfaceMetric(iface.Id, uint32(metric))
default:
usage()
}
diff --git a/garnet/go/src/netstack/ifconfig/ifconfig_test.go b/garnet/go/src/netstack/ifconfig/ifconfig_test.go
index 8f5e4bd..f1eaeb86 100644
--- a/garnet/go/src/netstack/ifconfig/ifconfig_test.go
+++ b/garnet/go/src/netstack/ifconfig/ifconfig_test.go
@@ -97,7 +97,7 @@
if err == nil {
t.Errorf("ifconfig route add returned success with neither gateway or iface specified. output: \n%s", out)
}
- expected = "Error adding route to route table"
+ expected = "Error adding route"
if !strings.Contains(string(out), expected) {
t.Errorf("want `ifconfig route add` to print \"%s\", got \"%s\"", expected, out)
}
diff --git a/garnet/go/src/netstack/main.go b/garnet/go/src/netstack/main.go
index a56fd2c..a35761a 100644
--- a/garnet/go/src/netstack/main.go
+++ b/garnet/go/src/netstack/main.go
@@ -80,10 +80,8 @@
var netstackService netstack.NetstackService
- ns.OnInterfacesChanged = func(interfaces2 []netstack.NetInterface2) {
- connectivity.InferAndNotify(interfaces2)
- // Handle deprecated version OnInterfacesChanged first.
- interfaces := interfaces2ListToInterfacesList(interfaces2)
+ ns.OnInterfacesChanged = func(interfaces []netstack.NetInterface) {
+ connectivity.InferAndNotify(interfaces)
for _, key := range netstackService.BindingKeys() {
if p, ok := netstackService.EventProxyFor(key); ok {
if err := p.OnInterfacesChanged(interfaces); err != nil {
@@ -91,15 +89,6 @@
}
}
}
- // Now the new OnInterfacesChanged2 version.
- // TODO(NET-2078): Remove this once Chromium stops using netstack.fidl.
- for _, key := range netstackService.BindingKeys() {
- if p, ok := netstackService.EventProxyFor(key); ok {
- if err := p.OnInterfacesChanged2(interfaces2); err != nil {
- log.Printf("OnInterfacesChanged2 failed: %v", err)
- }
- }
- }
}
var inspectService inspect.InspectService
@@ -123,16 +112,12 @@
// Prevents clients from having to race GetInterfaces / InterfacesChanged.
if p, ok := netstackService.EventProxyFor(k); ok {
ns.mu.Lock()
- interfaces2 := ns.getNetInterfaces2Locked()
- interfaces := interfaces2ListToInterfacesList(interfaces2)
+ interfaces := ns.getInterfacesLocked()
ns.mu.Unlock()
if err := p.OnInterfacesChanged(interfaces); err != nil {
log.Printf("OnInterfacesChanged failed: %v", err)
}
- if err := p.OnInterfacesChanged2(interfaces2); err != nil {
- log.Printf("OnInterfacesChanged2 failed: %v", err)
- }
}
return nil
})
diff --git a/garnet/go/src/netstack/netiface/netiface.go b/garnet/go/src/netstack/netiface/netiface.go
index 803fd1e2..faea8db 100644
--- a/garnet/go/src/netstack/netiface/netiface.go
+++ b/garnet/go/src/netstack/netiface/netiface.go
@@ -5,20 +5,75 @@
package netiface
import (
- "netstack/routes"
-
"github.com/google/netstack/tcpip"
)
-// TODO(NET-1223):This should be moved into netstack.go.
type NIC struct {
- ID tcpip.NICID
- Addr tcpip.Address
- IsDynamicAddr bool
- Name string
- Features uint32
- Metric routes.Metric // used as a default for routes that use this NIC
- Netmask tcpip.AddressMask
- DNSServers []tcpip.Address
- Ipv6addrs []tcpip.Address
+ ID tcpip.NICID
+ Addr tcpip.Address
+ Name string
+ Features uint32
+ Netmask tcpip.AddressMask
+ Routes []tcpip.Route
+ DNSServers []tcpip.Address
+ Ipv6addrs []tcpip.Address
+}
+
+func IsAny(a tcpip.Address) bool {
+ for i := 0; i < len(a); i++ {
+ if a[i] != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func hasGateway(r *tcpip.Route) bool {
+ return r.Gateway != ""
+}
+
+func prefixLength(mask tcpip.AddressMask) (len int) {
+ for _, b := range []byte(mask) {
+ for i := uint(0); i < 8; i++ {
+ if b&(1<<i) != 0 {
+ len++
+ } else {
+ return len
+ }
+ }
+ }
+ return len
+}
+
+// Less is the sorting function used for routes.
+func Less(ri, rj *tcpip.Route, nics map[tcpip.NICID]*NIC) bool {
+ ni, nj := nics[ri.NIC], nics[rj.NIC]
+ // If only one of them has a route for specific address (i.e. not a route
+ // for Any destination), that element should sort before the other.
+ if IsAny(ri.Destination) != IsAny(rj.Destination) {
+ return !IsAny(ri.Destination)
+ }
+ // If only one of them has a gateway, that element should sort before
+ // the other.
+ if hasGateway(ri) != hasGateway(rj) {
+ return hasGateway(ri)
+ }
+ // If both have gateways and only one is for a specific address, that
+ // element should sort before the other.
+ if IsAny(ri.Gateway) != IsAny(rj.Gateway) {
+ return !IsAny(ri.Gateway)
+ }
+ // If only one them has a NIC with an IP address, that element should sort
+ // before the other.
+ if (ni.Addr != "") != (nj.Addr != "") {
+ return ni.Addr != ""
+ }
+ // If one has a more specific netmask (longer prefix len), that element
+ // should sort before the other.
+ li, lj := prefixLength(ri.Mask), prefixLength(rj.Mask)
+ if len(ri.Mask) == len(rj.Mask) && li != lj {
+ return li > lj
+ }
+ // Otherwise, sort them by the IDs of their NICs.
+ return ri.NIC < rj.NIC
}
diff --git a/garnet/go/src/netstack/netiface/netiface_test.go b/garnet/go/src/netstack/netiface/netiface_test.go
new file mode 100644
index 0000000..48921e0
--- /dev/null
+++ b/garnet/go/src/netstack/netiface/netiface_test.go
@@ -0,0 +1,420 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package netiface_test
+
+import (
+ "net"
+ "sort"
+ "strings"
+ "testing"
+
+ "netstack/fidlconv"
+ "netstack/netiface"
+ "netstack/util"
+
+ netfidl "fidl/fuchsia/net"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/netstack/tcpip"
+)
+
+func indexedByID(nics []netiface.NIC) map[tcpip.NICID]*netiface.NIC {
+ res := make(map[tcpip.NICID]*netiface.NIC)
+ for i, v := range nics {
+ res[v.ID] = &nics[i]
+ }
+ return res
+}
+
+func setID(n *netiface.NIC, id tcpip.NICID) {
+ n.ID = id
+ for i := range n.Routes {
+ n.Routes[i].NIC = id
+ }
+}
+
+func setGateway(n *netiface.NIC, gateway tcpip.Address) {
+ for i := range n.Routes {
+ n.Routes[i].Gateway = gateway
+ }
+}
+
+func NewLoopback() netiface.NIC {
+ return netiface.NIC{
+ Addr: util.Parse("127.0.0.1"),
+ Routes: []tcpip.Route{
+ {
+ Destination: util.Parse("127.0.0.1"),
+ Mask: "\xff\xff\xff\xff",
+ },
+ {
+ Destination: util.Parse("::1"),
+ Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
+ },
+ },
+ }
+}
+
+func NewAnyDest() netiface.NIC {
+ return netiface.NIC{
+ Routes: []tcpip.Route{
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ },
+ },
+ }
+}
+
+func TestLoopbackBeforeAny(t *testing.T) {
+ var nics []netiface.NIC
+
+ // Create NIC 1 for any destination.
+ n := NewAnyDest()
+ setID(&n, 1)
+ nics = append(nics, n)
+
+ // Create NIC 2 for loopback.
+ n = NewLoopback()
+ setID(&n, 2)
+ nics = append(nics, n)
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ expected := []tcpip.Route{
+ {
+ Destination: util.Parse("127.0.0.1"),
+ Mask: "\xff\xff\xff\xff",
+ NIC: 2,
+ },
+ {
+ Destination: util.Parse("::1"),
+ Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
+ NIC: 2,
+ },
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 1,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 1,
+ },
+ }
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func TestGatewayBeforeAddr(t *testing.T) {
+ var nics []netiface.NIC
+
+ // Create NIC 1 for any destination with an address.
+ n := NewAnyDest()
+ setID(&n, 1)
+ n.Addr = util.Parse("1.2.3.4")
+ nics = append(nics, n)
+
+ // Create NIC 2 for any destination with a gateway.
+ n = NewAnyDest()
+ setID(&n, 2)
+ setGateway(&n, util.Parse("1.1.1.1"))
+ nics = append(nics, n)
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ expected := []tcpip.Route{
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ Gateway: util.Parse("1.1.1.1"),
+ NIC: 2,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ Gateway: util.Parse("1.1.1.1"),
+ NIC: 2,
+ },
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 1,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 1,
+ },
+ }
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func TestAddrBeforeAny(t *testing.T) {
+ var nics []netiface.NIC
+
+ // Create NIC 1 for any destination.
+ n := NewAnyDest()
+ setID(&n, 1)
+ nics = append(nics, n)
+
+ // Create NIC 2 for any destination with an address.
+ n = NewAnyDest()
+ setID(&n, 2)
+ n.Addr = util.Parse("1.2.3.4")
+ nics = append(nics, n)
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ expected := []tcpip.Route{
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 2,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 2,
+ },
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 1,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 1,
+ },
+ }
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func TestSortByIDAsFallback(t *testing.T) {
+ var nics []netiface.NIC
+
+ // Create NIC 2 for any destination with an address.
+ n := NewAnyDest()
+ setID(&n, 2)
+ n.Addr = util.Parse("1.2.3.4")
+ nics = append(nics, n)
+
+ // Create NIC 1 for any destination with an address.
+ n = NewAnyDest()
+ setID(&n, 1)
+ n.Addr = util.Parse("::1")
+ nics = append(nics, n)
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ expected := []tcpip.Route{
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 1,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 1,
+ },
+ {
+ Destination: tcpip.Address(strings.Repeat("\x00", 4)),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 4)),
+ NIC: 2,
+ },
+ {
+ Destination: util.Parse("::"),
+ Mask: tcpip.AddressMask(strings.Repeat("\x00", 16)),
+ NIC: 2,
+ },
+ }
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func TestSpecificGatewayBeforeAnyGateway(t *testing.T) {
+ nics := []netiface.NIC{
+ {
+ ID: 1,
+ Routes: []tcpip.Route{
+ {
+ Gateway: util.Parse("192.168.42.1"),
+ NIC: 1,
+ },
+ {
+ Gateway: util.Parse("::"),
+ NIC: 1,
+ },
+ },
+ },
+ {
+ ID: 2,
+ Routes: []tcpip.Route{
+ {
+ Gateway: util.Parse("10.0.1.1"),
+ NIC: 2,
+ },
+ {
+ Gateway: util.Parse("::"),
+ NIC: 2,
+ },
+ },
+ },
+ }
+
+ expected := []tcpip.Route{
+ {
+ Gateway: util.Parse("192.168.42.1"),
+ NIC: 1,
+ },
+ {
+ Gateway: util.Parse("10.0.1.1"),
+ NIC: 2,
+ },
+ {
+ Gateway: util.Parse("::"),
+ NIC: 1,
+ },
+ {
+ Gateway: util.Parse("::"),
+ NIC: 2,
+ },
+ }
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func TestSpecificMaskFirst(t *testing.T) {
+ nics := []netiface.NIC{
+ {
+ ID: 1,
+ Routes: []tcpip.Route{
+ {
+ Gateway: util.Parse("192.168.0.1"),
+ Mask: "\xff\xff\x00\x00",
+ NIC: 1,
+ },
+ },
+ },
+ {
+ ID: 1,
+ Routes: []tcpip.Route{
+ {
+ Gateway: util.Parse("192.168.42.1"),
+ Mask: "\xff\xff\xff\x00",
+ NIC: 1,
+ },
+ },
+ },
+ }
+
+ expected := []tcpip.Route{
+ {
+ Gateway: util.Parse("192.168.42.1"),
+ Mask: "\xff\xff\xff\x00",
+ NIC: 1,
+ },
+ {
+ Gateway: util.Parse("192.168.0.1"),
+ Mask: "\xff\xff\x00\x00",
+ NIC: 1,
+ },
+ }
+
+ var routes []tcpip.Route
+ for _, nic := range nics {
+ routes = append(routes, nic.Routes...)
+ }
+ indexedByID := indexedByID(nics)
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], indexedByID)
+ })
+
+ if diff := cmp.Diff(expected, routes); diff != "" {
+ t.Errorf("(-want +got)\n%s", diff)
+ }
+}
+
+func newV4Address(a, b, c, d uint8) netfidl.IpAddress {
+ return fidlconv.ToNetIpAddress(tcpip.Address(net.IPv4(a, b, c, d).To4()))
+}
+
+var isAnyTests = []struct {
+ addr netfidl.IpAddress
+ res bool
+}{
+ {
+ addr: newV4Address(0, 0, 0, 0),
+ res: true,
+ },
+ {
+ addr: newV4Address(127, 0, 0, 1),
+ res: false,
+ },
+}
+
+func TestIsAny(t *testing.T) {
+ for _, tst := range isAnyTests {
+ if res := netiface.IsAny(fidlconv.ToTCPIPAddress(tst.addr)); res != tst.res {
+ t.Errorf("expected netiface.IsAny(%+v) to be %v, got %v", tst.addr, tst.res, res)
+ }
+ }
+}
diff --git a/garnet/go/src/netstack/netstack.go b/garnet/go/src/netstack/netstack.go
index 41eb268..0e7d94c 100644
--- a/garnet/go/src/netstack/netstack.go
+++ b/garnet/go/src/netstack/netstack.go
@@ -8,6 +8,7 @@
"context"
"fmt"
"log"
+ "sort"
"strings"
"sync"
@@ -19,7 +20,6 @@
"netstack/link/eth"
"netstack/link/stats"
"netstack/netiface"
- "netstack/routes"
"netstack/util"
"fidl/fuchsia/devicesettings"
@@ -42,18 +42,8 @@
deviceSettingsManagerNodenameKey = "DeviceName"
defaultNodename = "fuchsia-unset-device-name"
- defaultInterfaceMetric routes.Metric = 100
-
- metricNotSet routes.Metric = 0
-
- lowPriorityRoute routes.Metric = 99999
-
ipv4Loopback tcpip.Address = "\x7f\x00\x00\x01"
ipv6Loopback tcpip.Address = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
-
- // Values used to indicate no IP is assigned to an interface.
- zeroIpAddr tcpip.Address = header.IPv4Any
- zeroIpMask tcpip.AddressMask = "\xff\xff\xff\xff"
)
// A Netstack tracks all of the running state of the network stack.
@@ -66,7 +56,6 @@
mu struct {
sync.Mutex
stack *stack.Stack
- routeTable routes.RouteTable
transactionRequest *netstack.RouteTableTransactionInterfaceRequest
countNIC tcpip.NICID
ifStates map[tcpip.NICID]*ifState
@@ -75,8 +64,7 @@
filter *filter.Filter
- // This calls both OnInterfacesChanged() and OnInterfacesChanged2() FIDL APIs.
- OnInterfacesChanged func([]netstack.NetInterface2)
+ OnInterfacesChanged func([]netstack.NetInterface)
}
// Each ifState tracks the state of a network interface.
@@ -112,8 +100,7 @@
bridgeable *bridge.BridgeableEndpoint
}
-// defaultRoutes returns the IPv4 and IPv6 default routes.
-func defaultRoutes(nicid tcpip.NICID, gateway tcpip.Address) []tcpip.Route {
+func defaultRouteTable(nicid tcpip.NICID, gateway tcpip.Address) []tcpip.Route {
return []tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", 4)),
@@ -138,114 +125,11 @@
}
}
-// AddRoute adds a single route to the route table in a sorted fashion. This
-// takes the lock.
-func (ns *Netstack) AddRoute(r tcpip.Route, metric routes.Metric, dynamic bool) error {
- log.Printf("adding route %+v metric:%d dynamic=%v", r, metric, dynamic)
- ns.mu.Lock()
- defer ns.mu.Unlock()
- return ns.AddRouteLocked(r, metric, dynamic)
-}
-
-// AddRouteLocked adds a single route to the route table in a sorted fashion. It
-// assumes the lock has already been taken.
-func (ns *Netstack) AddRouteLocked(r tcpip.Route, metric routes.Metric, dynamic bool) error {
- return ns.AddRoutesLocked([]tcpip.Route{r}, metric, dynamic)
-}
-
-// AddRoutesLocked adds one or more routes to the route table in a sorted
-// fashion. It assumes the lock has already been taken.
-func (ns *Netstack) AddRoutesLocked(rs []tcpip.Route, metric routes.Metric, dynamic bool) error {
- metricTracksInterface := false
- if metric == metricNotSet {
- metricTracksInterface = true
- }
-
- for _, r := range rs {
- // If we don't have an interface set, find it using the gateway address.
- if r.NIC == 0 {
- nic, err := ns.mu.routeTable.FindNIC(r.Gateway)
- if err != nil {
- return fmt.Errorf("error finding NIC for gateway %v: %s", r.Gateway, err)
- }
- r.NIC = nic
- }
-
- ifs, ok := ns.mu.ifStates[r.NIC]
- if !ok {
- return fmt.Errorf("error getting ifState for NIC %d, not in map", r.NIC)
- }
-
- enabled := ifs.mu.state == link.StateStarted
- if metricTracksInterface {
- metric = ifs.mu.nic.Metric
- }
-
- ns.mu.routeTable.AddRoute(r, metric, metricTracksInterface, dynamic, enabled)
- }
- ns.mu.stack.SetRouteTable(ns.mu.routeTable.GetNetstackTable())
- return nil
-}
-
-// DelRoute deletes a single route from the route table. This takes the lock.
-func (ns *Netstack) DelRoute(r tcpip.Route) error {
- log.Printf("deleting route %+v", r)
- ns.mu.Lock()
- defer ns.mu.Unlock()
- return ns.DelRouteLocked(r)
-}
-
-// DelRoute deletes a single route from the route table. It assumes the lock has
-// already been taken.
-func (ns *Netstack) DelRouteLocked(r tcpip.Route) error {
- if err := ns.mu.routeTable.DelRoute(r); err != nil {
- return fmt.Errorf("error deleting route, %s", err)
- }
- ns.mu.stack.SetRouteTable(ns.mu.routeTable.GetNetstackTable())
- return nil
-}
-
-// GetExtendedRouteTable returns a copy of the current extended route table.
-// This takes the lock.
-func (ns *Netstack) GetExtendedRouteTable() []routes.ExtendedRoute {
- ns.mu.Lock()
- defer ns.mu.Unlock()
- return ns.mu.routeTable.GetExtendedRouteTable()
-}
-
-// UpdateRoutesByInterfaceLocked applies update actions to the routes for a
-// given interface. It assumes the lock has already been taken.
-func (ns *Netstack) UpdateRoutesByInterfaceLocked(nicid tcpip.NICID, action routes.Action) {
- ns.mu.routeTable.UpdateRoutesByInterface(nicid, action)
- ns.mu.stack.SetRouteTable(ns.mu.routeTable.GetNetstackTable())
-}
-
-// UpdateInterfaceMetric changes the metric for an interface and updates all
-// routes tracking that interface metric. This takes the lock.
-func (ns *Netstack) UpdateInterfaceMetric(nicid tcpip.NICID, metric routes.Metric) error {
- log.Printf("update interface metric for NIC %d to metric=%d", nicid, metric)
-
- ns.mu.Lock()
- defer ns.mu.Unlock()
-
- ifState, ok := ns.mu.ifStates[tcpip.NICID(nicid)]
- if !ok {
- return fmt.Errorf("error getting ifState for NIC %d, not in map", nicid)
- }
- ifState.updateMetric(metric)
-
- ns.mu.routeTable.UpdateMetricByInterface(nicid, metric)
- ns.mu.stack.SetRouteTable(ns.mu.routeTable.GetNetstackTable())
- return nil
-}
-
func (ns *Netstack) removeInterfaceAddress(nic tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, prefixLen uint8) error {
subnet, err := toSubnet(addr, prefixLen)
if err != nil {
return fmt.Errorf("error parsing subnet format for NIC ID %d: %s", nic, err)
}
- route := subnetRoute(addr, subnet.Mask(), nic)
- log.Printf("removing static IP %v/%d from NIC %d, deleting subnet route %+v", addr, prefixLen, nic, route)
ns.mu.Lock()
if err := func() error {
@@ -259,35 +143,33 @@
return fmt.Errorf("no such subnet %+v for NIC ID %d", subnet, nic)
}
- ns.DelRouteLocked(route)
-
if err := ns.mu.stack.RemoveAddress(nic, addr); err != nil {
return fmt.Errorf("error removing address %s from NIC ID %d: %s", addr, nic, err)
}
- newAddr := zeroIpAddr
- newNetmask := zeroIpMask
- // Check if the NIC still has other primary IPs and use that one.
- if mainAddr, subnet, err := ns.mu.stack.GetMainNICAddress(nic, protocol); err == nil {
- newAddr = mainAddr
- newNetmask = subnet.Mask()
- if newNetmask == "" {
- addressSize := len(newAddr) * 8
- newNetmask = util.CIDRMask(addressSize, addressSize)
+ if addr, subnet, err := ns.mu.stack.GetMainNICAddress(nic, protocol); err != nil {
+ return fmt.Errorf("error querying NIC ID %d, error: %s", nic, err)
+ } else {
+ netmask := subnet.Mask()
+ if netmask == "" {
+ addressSize := len(addr) * 8
+ netmask = util.CIDRMask(addressSize, addressSize)
+ }
+
+ if ifs, ok := ns.mu.ifStates[nic]; !ok {
+ panic(fmt.Sprintf("Interface state table out of sync: NIC [%d] known to third_party/netstack not found in garnet/netstack", nic))
+ } else {
+ ifs.staticAddressChanged(addr, netmask)
+ ifs.ns.mu.stack.SetRouteTable(ifs.ns.flattenRouteTablesLocked())
}
}
- ifs, ok := ns.mu.ifStates[nic]
- if !ok {
- panic(fmt.Sprintf("Interface state table out of sync: NIC [%d] known to third_party/netstack not found in garnet/netstack", nic))
- }
- ifs.staticAddressChanged(newAddr, newNetmask)
return nil
}(); err != nil {
ns.mu.Unlock()
return err
}
- interfaces := ns.getNetInterfaces2Locked()
+ interfaces := ns.getNetInterfacesLocked()
ns.mu.Unlock()
ns.OnInterfacesChanged(interfaces)
return nil
@@ -303,8 +185,6 @@
if err != nil {
return fmt.Errorf("error parsing subnet format for NIC ID %d: %s", nic, err)
}
- route := subnetRoute(addr, subnet.Mask(), nic)
- log.Printf("adding static IP %v/%d to NIC %d, creating subnet route %+v with metric=<not-set>, dynamic=false", addr, prefixLen, nic, route)
ns.mu.Lock()
if err := func() error {
@@ -320,9 +200,7 @@
panic(fmt.Sprintf("Interface state table out of sync: NIC [%d] known to third_party/netstack not found in garnet/netstack", nic))
} else {
ifs.staticAddressChanged(addr, subnet.Mask())
- if err := ns.AddRouteLocked(route, metricNotSet, false /* dynamic */); err != nil {
- return fmt.Errorf("error adding subnet route %v to NIC ID %d: %s", route, nic, err)
- }
+ ifs.ns.mu.stack.SetRouteTable(ifs.ns.flattenRouteTablesLocked())
}
return nil
}(); err != nil {
@@ -330,22 +208,17 @@
return err
}
- interfaces := ns.getNetInterfaces2Locked()
+ interfaces := ns.getNetInterfacesLocked()
ns.mu.Unlock()
ns.OnInterfacesChanged(interfaces)
return nil
}
-func (ifs *ifState) updateMetric(metric routes.Metric) {
- ifs.mu.Lock()
- ifs.mu.nic.Metric = metric
- ifs.mu.Unlock()
-}
-
func (ifs *ifState) staticAddressChanged(newAddr tcpip.Address, netmask tcpip.AddressMask) {
ifs.mu.Lock()
ifs.mu.nic.Addr = newAddr
ifs.mu.nic.Netmask = netmask
+ ifs.mu.nic.Routes = append(ifs.mu.nic.Routes, subnetRoute(newAddr, netmask, ifs.mu.nic.ID))
ifs.mu.Unlock()
}
@@ -364,23 +237,18 @@
log.Printf("NIC %s: DHCP acquired IP %s for %s", ifs.mu.nic.Name, newAddr, config.LeaseLength)
log.Printf("NIC %s: Adding DNS servers: %v", ifs.mu.nic.Name, config.DNS)
+ // Update default route with new gateway.
ifs.mu.Lock()
+ ifs.mu.nic.Routes = defaultRouteTable(ifs.mu.nic.ID, config.Gateway)
+ ifs.mu.nic.Routes = append(ifs.mu.nic.Routes, subnetRoute(newAddr, config.SubnetMask, ifs.mu.nic.ID))
ifs.mu.nic.Netmask = config.SubnetMask
ifs.mu.nic.Addr = newAddr
- ifs.mu.nic.IsDynamicAddr = true
ifs.mu.nic.DNSServers = config.DNS
ifs.mu.Unlock()
- // Add a default route and a route for the local subnet.
- rs := defaultRoutes(ifs.mu.nic.ID, config.Gateway)
- rs = append(rs, subnetRoute(newAddr, config.SubnetMask, ifs.mu.nic.ID))
- log.Printf("adding routes %+v with metric=<not-set> dynamic=true", rs)
-
ifs.ns.mu.Lock()
- if err := ifs.ns.AddRoutesLocked(rs, metricNotSet, true /* dynamic */); err != nil {
- log.Printf("error adding routes for DHCP address/gateway: %v", err)
- }
- interfaces := ifs.ns.getNetInterfaces2Locked()
+ ifs.ns.mu.stack.SetRouteTable(ifs.ns.flattenRouteTablesLocked())
+ interfaces := ifs.ns.getNetInterfacesLocked()
ifs.ns.mu.Unlock()
ifs.ns.dnsClient.SetRuntimeServers(ifs.ns.getRuntimeDNSServerRefs())
@@ -431,49 +299,54 @@
// - remove link endpoint
// - reclaim NICID?
- if ifs.mu.nic.IsDynamicAddr || s == link.StateClosed {
- log.Printf("removing IP from NIC %d", ifs.mu.nic.ID)
- ifs.mu.nic.Netmask = zeroIpMask
- ifs.mu.nic.Addr = zeroIpAddr
- ifs.mu.nic.DNSServers = nil
- }
-
- if s == link.StateClosed {
- // The interface is removed, force all of its routes to be removed.
- ifs.ns.UpdateRoutesByInterfaceLocked(ifs.mu.nic.ID, routes.ActionDeleteAll)
- } else {
- // The interface is down, delete dynamic routes, disable static ones.
- ifs.ns.UpdateRoutesByInterfaceLocked(ifs.mu.nic.ID, routes.ActionDeleteDynamicDisableStatic)
- }
+ ifs.mu.nic.Routes = nil
+ ifs.mu.nic.Netmask = "\xff\xff\xff\xff"
+ ifs.mu.nic.Addr = "\x00\x00\x00\x00"
+ ifs.mu.nic.DNSServers = nil
case link.StateStarted:
log.Printf("NIC %s: starting", ifs.mu.nic.Name)
ifs.ctx, ifs.cancel = context.WithCancel(context.Background())
- // Re-enable static routes out this interface.
- ifs.ns.UpdateRoutesByInterfaceLocked(ifs.mu.nic.ID, routes.ActionEnableStatic)
+ ifs.mu.nic.Routes = defaultRouteTable(ifs.mu.nic.ID, "")
if ifs.mu.dhcp.enabled {
ifs.mu.dhcp.cancel()
ifs.runDHCPLocked()
}
- // TODO(ckuiper): Remove this, as we shouldn't create default routes w/o a
- // gateway given. Before doing so make sure nothing is still relying on
- // this.
- // Update the state before adding the routes, so they are properly enabled.
- ifs.mu.state = s
- if err := ifs.ns.AddRoutesLocked(defaultRoutes(ifs.mu.nic.ID, ""), lowPriorityRoute, true /* dynamic */); err != nil {
- log.Printf("error adding default routes: %v", err)
- }
}
ifs.mu.state = s
ifs.mu.Unlock()
- interfaces := ifs.ns.getNetInterfaces2Locked()
+ ifs.ns.mu.stack.SetRouteTable(ifs.ns.flattenRouteTablesLocked())
+
+ interfaces := ifs.ns.getNetInterfacesLocked()
ifs.ns.mu.Unlock()
ifs.ns.dnsClient.SetRuntimeServers(ifs.ns.getRuntimeDNSServerRefs())
ifs.ns.OnInterfacesChanged(interfaces)
}
+func (ns *Netstack) flattenRouteTablesLocked() []tcpip.Route {
+ routes := make([]tcpip.Route, 0)
+ nics := make(map[tcpip.NICID]*netiface.NIC)
+ for _, ifs := range ns.mu.ifStates {
+ ifs.mu.Lock()
+ routes = append(routes, ifs.mu.nic.Routes...)
+ nics[ifs.mu.nic.ID] = ifs.mu.nic
+ ifs.mu.Unlock()
+ }
+ sort.Slice(routes, func(i, j int) bool {
+ return netiface.Less(&routes[i], &routes[j], nics)
+ })
+ if debug {
+ for i, ifs := range ns.mu.ifStates {
+ log.Printf("[%v] nicid: %v, addr: %v, routes: %v",
+ i, ifs.mu.nic.ID, ifs.mu.nic.Addr, ifs.mu.nic.Routes)
+ }
+ }
+
+ return routes
+}
+
// Return a slice of references to each NIC's DNS servers.
// The caller takes ownership of the returned slice.
func (ns *Netstack) getRuntimeDNSServerRefs() []*[]tcpip.Address {
@@ -551,7 +424,18 @@
Addr: ipv4Loopback,
Netmask: tcpip.AddressMask(strings.Repeat("\xff", len(ipv4Loopback))),
Features: ethernet.InfoFeatureLoopback,
- Metric: defaultInterfaceMetric,
+ Routes: []tcpip.Route{
+ {
+ Destination: ipv4Loopback,
+ Mask: tcpip.AddressMask(strings.Repeat("\xff", 4)),
+ NIC: nicid,
+ },
+ {
+ Destination: ipv6Loopback,
+ Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
+ NIC: nicid,
+ },
+ },
}
nic.Name = "lo"
@@ -590,24 +474,7 @@
return fmt.Errorf("loopback: adding ipv6 address failed: %v", err)
}
- err := ns.AddRoutesLocked(
- []tcpip.Route{
- {
- Destination: ipv4Loopback,
- Mask: tcpip.AddressMask(strings.Repeat("\xff", 4)),
- NIC: nicid,
- },
- {
- Destination: ipv6Loopback,
- Mask: tcpip.AddressMask(strings.Repeat("\xff", 16)),
- NIC: nicid,
- },
- },
- metricNotSet, /* use interface metric */
- false /* dynamic */)
- if err != nil {
- return fmt.Errorf("loopback: adding routes failed: %v", err)
- }
+ ns.mu.stack.SetRouteTable(ns.flattenRouteTablesLocked())
return nil
}
@@ -682,9 +549,8 @@
}
ifs.mu.state = link.StateUnknown
ifs.mu.nic = &netiface.NIC{
- Addr: zeroIpAddr,
- Netmask: zeroIpMask,
- Metric: defaultInterfaceMetric,
+ Addr: "\x00\x00\x00\x00",
+ Netmask: "\xff\xff\xff\xff",
}
ifs.mu.dhcp.running = func() bool { return false }
ifs.mu.dhcp.cancel = func() {}
@@ -739,11 +605,14 @@
ifs.mu.Lock()
ifs.mu.nic.ID = nicid
+ ifs.mu.nic.Routes = defaultRouteTable(nicid, "")
ifs.mu.nic.Ipv6addrs = []tcpip.Address{lladdr}
ifs.statsEP.Nic = ifs.mu.nic
ifs.mu.dhcp.Client = dhcp.NewClient(ns.mu.stack, nicid, linkAddr, ifs.dhcpAcquired)
ifs.mu.Unlock()
+ // Add default route. This will get clobbered later when we get a DHCP response.
+ ns.mu.stack.SetRouteTable(ns.flattenRouteTablesLocked())
ns.mu.Unlock()
return ifs, finalize(ifs)
diff --git a/garnet/go/src/netstack/netstack_service.go b/garnet/go/src/netstack/netstack_service.go
index 0714fc0..27c44f3 100644
--- a/garnet/go/src/netstack/netstack_service.go
+++ b/garnet/go/src/netstack/netstack_service.go
@@ -14,7 +14,6 @@
"netstack/fidlconv"
"netstack/link"
- "netstack/routes"
"fidl/fuchsia/hardware/ethernet"
"fidl/fuchsia/net"
@@ -38,32 +37,12 @@
return out
}
-// interfaces2ListToInterfacesList converts a NetInterface2 list into a
-// NetInterface one.
-func interfaces2ListToInterfacesList(ifs2 []netstack.NetInterface2) []netstack.NetInterface {
- ifs := make([]netstack.NetInterface, 0, len(ifs2))
- for _, e2 := range ifs2 {
- ifs = append(ifs, netstack.NetInterface{
- Id: e2.Id,
- Flags: e2.Flags,
- Features: e2.Features,
- Name: e2.Name,
- Addr: e2.Addr,
- Netmask: e2.Netmask,
- Broadaddr: e2.Broadaddr,
- Hwaddr: e2.Hwaddr,
- Ipv6addrs: e2.Ipv6addrs,
- })
- }
- return ifs
-}
-
-func (ns *Netstack) getNetInterfaces2Locked() []netstack.NetInterface2 {
+func (ns *Netstack) getNetInterfacesLocked() []netstack.NetInterface {
ifStates := ns.mu.ifStates
- interfaces := make([]netstack.NetInterface2, 0, len(ifStates))
+ interfaces := make([]netstack.NetInterface, 0, len(ifStates))
for _, ifs := range ifStates {
ifs.mu.Lock()
- netinterface, err := ifs.toNetInterface2Locked()
+ netinterface, err := ifs.toNetInterfaceLocked()
ifs.mu.Unlock()
if err != nil {
log.Print(err)
@@ -73,11 +52,11 @@
return interfaces
}
-func (ifs *ifState) toNetInterface2Locked() (netstack.NetInterface2, error) {
+func (ifs *ifState) toNetInterfaceLocked() (netstack.NetInterface, error) {
// Long-hand for: broadaddr = ifs.mu.nic.Addr | ^ifs.mu.nic.Netmask
broadaddr := []byte(ifs.mu.nic.Addr)
if len(ifs.mu.nic.Netmask) != len(ifs.mu.nic.Addr) {
- return netstack.NetInterface2{}, fmt.Errorf("address length doesn't match netmask: %+v\n", ifs.mu.nic)
+ return netstack.NetInterface{}, fmt.Errorf("address length doesn't match netmask: %+v\n", ifs.mu.nic)
}
for i := range broadaddr {
@@ -92,11 +71,10 @@
flags |= netstack.NetInterfaceFlagDhcp
}
- return netstack.NetInterface2{
+ return netstack.NetInterface{
Id: uint32(ifs.mu.nic.ID),
Flags: flags,
Features: ifs.mu.nic.Features,
- Metric: uint32(ifs.mu.nic.Metric),
Name: ifs.mu.nic.Name,
Addr: fidlconv.ToNetIpAddress(ifs.mu.nic.Addr),
Netmask: fidlconv.ToNetIpAddress(tcpip.Address(ifs.mu.nic.Netmask)),
@@ -106,8 +84,8 @@
}, nil
}
-func (ns *Netstack) getInterfaces2Locked() []netstack.NetInterface2 {
- out := ns.getNetInterfaces2Locked()
+func (ns *Netstack) getInterfacesLocked() []netstack.NetInterface {
+ out := ns.getNetInterfacesLocked()
sort.Slice(out, func(i, j int) bool {
return out[i].Id < out[j].Id
@@ -148,119 +126,88 @@
return out, netstack.NetErr{Status: netstack.StatusOk}, nil
}
-// GetInterfaces2 returns a list of interfaces.
-// TODO(NET-2078): Move this to GetInterfaces once Chromium stops using
-// netstack.fidl.
-func (ni *netstackImpl) GetInterfaces2() ([]netstack.NetInterface2, error) {
- ni.ns.mu.Lock()
- defer ni.ns.mu.Unlock()
- return ni.ns.getInterfaces2Locked(), nil
-}
-
-// GetInterfaces is a deprecated version that returns a list of interfaces in a
-// format that Chromium supports. The new version is GetInterfaces2 which
-// eventually will be renamed once Chromium is not using netstack.fidl anymore
-// and this deprecated version can be removed.
func (ni *netstackImpl) GetInterfaces() ([]netstack.NetInterface, error) {
ni.ns.mu.Lock()
defer ni.ns.mu.Unlock()
- // Get the new interface list and convert to the old one.
- return interfaces2ListToInterfacesList(ni.ns.getInterfaces2Locked()), nil
+ return ni.ns.getInterfacesLocked(), nil
}
-// TODO(NET-2078): Move this to GetRouteTable once Chromium stops using
-// netstack.fidl.
-func (ni *netstackImpl) GetRouteTable2() ([]netstack.RouteTableEntry2, error) {
- return nsToRouteTable2(ni.ns.GetExtendedRouteTable()), nil
-}
-
-// GetRouteTable is a deprecated version that returns the route table in a
-// format that Chromium supports. The new version is GetRouteTable2 which will
-// eventually be renamed once Chromium is not using netstack.fidl anymore and
-// this deprecated version can be removed.
func (ni *netstackImpl) GetRouteTable() ([]netstack.RouteTableEntry, error) {
- rt2 := nsToRouteTable2(ni.ns.GetExtendedRouteTable())
- rt := make([]netstack.RouteTableEntry, 0, len(rt2))
- for _, r2 := range rt2 {
- var gateway net.IpAddress
- if r2.Gateway != nil {
- gateway = *r2.Gateway
- }
- rt = append(rt, netstack.RouteTableEntry{
- Destination: r2.Destination,
- Netmask: r2.Netmask,
- Gateway: gateway,
- Nicid: r2.Nicid,
- })
- }
- return rt, nil
+ ni.ns.mu.Lock()
+ defer ni.ns.mu.Unlock()
+ table := ni.ns.mu.stack.GetRouteTable()
+ return nsToRouteTable(table)
}
-func nsToRouteTable2(table []routes.ExtendedRoute) (out []netstack.RouteTableEntry2) {
- for _, e := range table {
+func nsToRouteTable(table []tcpip.Route) ([]netstack.RouteTableEntry, error) {
+ out := []netstack.RouteTableEntry{}
+ for _, route := range table {
// Ensure that if any of the returned addresses are "empty",
// they still have the appropriate length.
l := 0
- if len(e.Route.Destination) > 0 {
- l = len(e.Route.Destination)
- } else if len(e.Route.Mask) > 0 {
- l = len(e.Route.Destination)
+ if len(route.Destination) > 0 {
+ l = len(route.Destination)
+ } else if len(route.Mask) > 0 {
+ l = len(route.Destination)
+ } else if len(route.Gateway) > 0 {
+ l = len(route.Gateway)
}
- dest := e.Route.Destination
- mask := e.Route.Mask
+ dest := route.Destination
+ mask := route.Mask
+ gateway := route.Gateway
if len(dest) == 0 {
dest = tcpip.Address(strings.Repeat("\x00", l))
}
if len(mask) == 0 {
mask = tcpip.AddressMask(strings.Repeat("\x00", l))
}
-
- var gatewayPtr *net.IpAddress
- if len(e.Route.Gateway) != 0 {
- gateway := fidlconv.ToNetIpAddress(e.Route.Gateway)
- gatewayPtr = &gateway
+ if len(gateway) == 0 {
+ gateway = tcpip.Address(strings.Repeat("\x00", l))
}
- out = append(out, netstack.RouteTableEntry2{
+
+ out = append(out, netstack.RouteTableEntry{
Destination: fidlconv.ToNetIpAddress(dest),
Netmask: fidlconv.ToNetIpAddress(tcpip.Address(mask)),
- Gateway: gatewayPtr,
- Nicid: uint32(e.Route.NIC),
- Metric: uint32(e.Metric),
+ Gateway: fidlconv.ToNetIpAddress(gateway),
+ Nicid: uint32(route.NIC),
})
}
- return out
+ return out, nil
}
-func routeToNs(r netstack.RouteTableEntry2) tcpip.Route {
- var gateway tcpip.Address
- if r.Gateway != nil {
- gateway = fidlconv.ToTCPIPAddress(*r.Gateway)
+func routeTableToNs(rt []netstack.RouteTableEntry) []tcpip.Route {
+ routes := make([]tcpip.Route, 0, len(rt))
+ for _, r := range rt {
+ routes = append(routes, tcpip.Route{
+ Destination: fidlconv.ToTCPIPAddress(r.Destination),
+ Mask: tcpip.AddressMask(fidlconv.ToTCPIPAddress(r.Netmask)),
+ Gateway: fidlconv.ToTCPIPAddress(r.Gateway),
+ NIC: tcpip.NICID(r.Nicid),
+ })
}
- return tcpip.Route{
- Destination: fidlconv.ToTCPIPAddress(r.Destination),
- Mask: tcpip.AddressMask(fidlconv.ToTCPIPAddress(r.Netmask)),
- Gateway: gateway,
- NIC: tcpip.NICID(r.Nicid),
- }
+
+ return routes
}
type routeTableTransactionImpl struct {
- ni *netstackImpl
+ ni *netstackImpl
+ routeTableCache []tcpip.Route
}
-func (i *routeTableTransactionImpl) AddRoute(r netstack.RouteTableEntry2) (int32, error) {
- err := i.ni.ns.AddRoute(routeToNs(r), routes.Metric(r.Metric), false /* not dynamic */)
- if err != nil {
- return int32(zx.ErrInvalidArgs), err
- }
- return int32(zx.ErrOk), nil
+func (i *routeTableTransactionImpl) GetRouteTable() ([]netstack.RouteTableEntry, error) {
+ return nsToRouteTable(i.routeTableCache)
}
-func (i *routeTableTransactionImpl) DelRoute(r netstack.RouteTableEntry2) (int32, error) {
- err := i.ni.ns.DelRoute(routeToNs(r))
- if err != nil {
- return int32(zx.ErrInvalidArgs), err
- }
+func (i *routeTableTransactionImpl) SetRouteTable(rt []netstack.RouteTableEntry) error {
+ routes := routeTableToNs(rt)
+ i.routeTableCache = routes
+ return nil
+}
+
+func (i *routeTableTransactionImpl) Commit() (int32, error) {
+ i.ni.ns.mu.Lock()
+ defer i.ni.ns.mu.Unlock()
+ i.ni.ns.mu.stack.SetRouteTable(i.routeTableCache)
return int32(zx.ErrOk), nil
}
@@ -287,7 +234,10 @@
ni.ns.mu.transactionRequest = &req
}
var routeTableService netstack.RouteTableTransactionService
- transaction := routeTableTransactionImpl{ni: ni}
+ transaction := routeTableTransactionImpl{
+ ni: ni,
+ routeTableCache: ni.ns.mu.stack.GetRouteTable(),
+ }
// We don't use the error handler to free the channel because it's
// possible that the peer closes the channel before our service has
// finished processing.
@@ -330,14 +280,6 @@
return netstack.NetErr{Status: netstack.StatusOk, Message: ""}, nil
}
-// SetInterfaceMetric updates the metric of an interface.
-func (ni *netstackImpl) SetInterfaceMetric(nicid uint32, metric uint32) (result netstack.NetErr, err error) {
- if err := ni.ns.UpdateInterfaceMetric(tcpip.NICID(nicid), routes.Metric(metric)); err != nil {
- return netstack.NetErr{Status: netstack.StatusUnknownInterface, Message: err.Error()}, nil
- }
- return netstack.NetErr{Status: netstack.StatusOk}, nil
-}
-
func (ni *netstackImpl) BridgeInterfaces(nicids []uint32) (netstack.NetErr, error) {
nics := make([]tcpip.NICID, len(nicids))
for i, n := range nicids {
diff --git a/garnet/go/src/netstack/netstack_service_impl_test.go b/garnet/go/src/netstack/netstack_service_impl_test.go
index 45b2a1c..1f0abb5 100644
--- a/garnet/go/src/netstack/netstack_service_impl_test.go
+++ b/garnet/go/src/netstack/netstack_service_impl_test.go
@@ -11,7 +11,6 @@
"syscall/zx/fidl"
"testing"
- "fidl/fuchsia/hardware/ethernet"
netfidl "fidl/fuchsia/net"
"fidl/fuchsia/netstack"
@@ -46,19 +45,7 @@
func TestRouteTableTransactions(t *testing.T) {
go fidl.Serve()
t.Run("no contentions", func(t *testing.T) {
- // Create a basic netstack instance with a single interface. We need at
- // least one interface in order to add routes.
- netstackServiceImpl := netstackImpl{ns: newNetstack(t)}
- eth := deviceForAddEth(ethernet.Info{}, t)
- ifs, err := netstackServiceImpl.ns.addEth("/fake/ethernet/device", netstack.InterfaceConfig{Name: "testdevice"}, ð)
- if err != nil {
- t.Fatal(err)
- }
-
- var originalTable []netstack.RouteTableEntry2
- originalTable, err = netstackServiceImpl.GetRouteTable2()
- AssertNoError(t, err)
-
+ netstackServiceImpl := MakeNetstackService()
req, transactionInterface, err := netstack.NewRouteTableTransactionInterfaceRequest()
AssertNoError(t, err)
@@ -70,67 +57,29 @@
t.Errorf("can't start a transaction")
}
+ rs, err := transactionInterface.GetRouteTable()
+ AssertNoError(t, err)
+
destinationAddress, destinationSubnet, err := net.ParseCIDR("1.2.3.4/24")
AssertNoError(t, err)
- gatewayAddress := net.ParseIP("5.6.7.8")
- if gatewayAddress == nil {
- t.Fatal("Cannot create gateway IP")
- }
- gateway := toIpAddress(gatewayAddress)
- newRouteTableEntry2 := netstack.RouteTableEntry2{
+ gatewayAddress, _, err := net.ParseCIDR("5.6.7.8/32")
+ newRouteTableEntry := netstack.RouteTableEntry{
Destination: toIpAddress(destinationAddress),
Netmask: toIpAddress(net.IP(destinationSubnet.Mask)),
- Gateway: &gateway,
- Nicid: uint32(ifs.mu.nic.ID),
- Metric: 100,
+ Gateway: toIpAddress(gatewayAddress),
}
- success, err = transactionInterface.AddRoute(newRouteTableEntry2)
- AssertNoError(t, err)
- if zx.Status(success) != zx.ErrOk {
- t.Fatal("can't add new route entry")
- }
+ newRouteTable := append(rs, newRouteTableEntry)
+ AssertNoError(t, transactionInterface.SetRouteTable(newRouteTable))
- // New table should contain the one route we just added.
- actualTable2, err := netstackServiceImpl.GetRouteTable2()
+ _, err = transactionInterface.Commit()
AssertNoError(t, err)
- if diff := cmp.Diff(actualTable2[0], newRouteTableEntry2, cmpopts.IgnoreTypes(struct{}{})); diff != "" {
+
+ actual, err := netstackServiceImpl.GetRouteTable()
+ AssertNoError(t, err)
+ if diff := cmp.Diff(actual, newRouteTable, cmpopts.IgnoreTypes(struct{}{})); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
-
- // Verify deprecated GetRouteTable() function returns equal entries.
- expectedRouteTableEntry := netstack.RouteTableEntry{
- Destination: newRouteTableEntry2.Destination,
- Netmask: newRouteTableEntry2.Netmask,
- Gateway: *newRouteTableEntry2.Gateway,
- Nicid: newRouteTableEntry2.Nicid,
- // no metric
- }
- actualTable, err := netstackServiceImpl.GetRouteTable()
- AssertNoError(t, err)
- if diff := cmp.Diff(actualTable[0], expectedRouteTableEntry, cmpopts.IgnoreTypes(struct{}{})); diff != "" {
- t.Errorf("(-want +got)\n%s", diff)
- }
-
- success, err = transactionInterface.DelRoute(newRouteTableEntry2)
- AssertNoError(t, err)
- if zx.Status(success) != zx.ErrOk {
- t.Error("can't delete route entry")
- }
-
- // New table should be empty.
- actualTable2, err = netstackServiceImpl.GetRouteTable2()
- AssertNoError(t, err)
- if len(actualTable2) != len(originalTable) {
- t.Errorf("got %v, want <nothing>", actualTable2)
- }
-
- // Same for deprecated route table.
- actualTable, err = netstackServiceImpl.GetRouteTable()
- AssertNoError(t, err)
- if len(actualTable) != len(originalTable) {
- t.Errorf("got %v, want <nothing>", actualTable)
- }
})
t.Run("contentions", func(t *testing.T) {
diff --git a/garnet/go/src/netstack/netstack_test.go b/garnet/go/src/netstack/netstack_test.go
index 847085b..7ee77ff 100644
--- a/garnet/go/src/netstack/netstack_test.go
+++ b/garnet/go/src/netstack/netstack_test.go
@@ -190,7 +190,7 @@
arp.ProtocolName,
}, nil, stack.Options{})
- ns.OnInterfacesChanged = func([]netstack.NetInterface2) {}
+ ns.OnInterfacesChanged = func([]netstack.NetInterface) {}
ipAddressConfig := netstack.IpAddressConfig{}
addr := fidlconv.ToNetIpAddress(testIpAddress)
subnet := net.Subnet{Addr: addr, PrefixLen: 32}
@@ -222,7 +222,7 @@
arp.ProtocolName,
}, nil, stack.Options{})
- ns.OnInterfacesChanged = func([]netstack.NetInterface2) {}
+ ns.OnInterfacesChanged = func([]netstack.NetInterface) {}
return ns
}
diff --git a/garnet/go/src/netstack/netstat/netstat.go b/garnet/go/src/netstack/netstat/netstat.go
index 76d0eab..0d43c545 100644
--- a/garnet/go/src/netstack/netstat/netstat.go
+++ b/garnet/go/src/netstack/netstat/netstat.go
@@ -118,7 +118,7 @@
}
func dumpStats(a *netstatApp) {
- nics, err := a.netstack.GetInterfaces2()
+ nics, err := a.netstack.GetInterfaces()
if err != nil {
errorf("Failed to get interfaces: %v\n.", err)
return
@@ -141,26 +141,22 @@
}
func dumpRouteTables(a *netstatApp) {
- entries, err := a.netstack.GetRouteTable2()
+ entries, err := a.netstack.GetRouteTable()
if err != nil {
errorf("Failed to get route table: %v\n", err)
return
}
for _, entry := range entries {
if netAddressZero(entry.Destination) {
- if entry.Gateway != nil && !netAddressZero(*entry.Gateway) {
- fmt.Printf("default via %s, ", netAddressToString(*entry.Gateway))
- } else {
- fmt.Printf("default through ")
- }
+ fmt.Printf("default via %s, ", netAddressToString(entry.Gateway))
} else {
fmt.Printf("Destination: %s, ", netAddressToString(entry.Destination))
fmt.Printf("Mask: %s, ", netAddressToString(entry.Netmask))
- if entry.Gateway != nil && !netAddressZero(*entry.Gateway) {
- fmt.Printf("Gateway: %s, ", netAddressToString(*entry.Gateway))
+ if !netAddressZero(entry.Gateway) {
+ fmt.Printf("Gateway: %s, ", netAddressToString(entry.Gateway))
}
}
- fmt.Printf("NICID: %d Metric: %v\n", entry.Nicid, entry.Metric)
+ fmt.Printf("NICID: %d\n", entry.Nicid)
}
}
diff --git a/garnet/go/src/netstack/routes/BUILD.gn b/garnet/go/src/netstack/routes/BUILD.gn
deleted file mode 100644
index dde999b1..0000000
--- a/garnet/go/src/netstack/routes/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/go/go_test.gni")
-
-go_test("netstack_routes_test") {
- gopackage = "netstack/routes"
-
- deps = [
- "//garnet/go/src/netstack:netstack_lib",
- ]
-}
diff --git a/garnet/go/src/netstack/routes/routes.go b/garnet/go/src/netstack/routes/routes.go
deleted file mode 100644
index 8d42566..0000000
--- a/garnet/go/src/netstack/routes/routes.go
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package routes
-
-import (
- "fmt"
- "log"
- "sort"
- "strings"
- "sync"
-
- "netstack/util"
-
- "github.com/google/netstack/tcpip"
- "github.com/google/netstack/tcpip/header"
-)
-
-const debug = false
-
-type Action uint32
-
-const (
- ActionDeleteAll Action = iota
- ActionDeleteDynamicDisableStatic
- ActionEnableStatic
-)
-
-// Metric is the metric used for sorting the route table. It acts as a
-// priority with a lower value being better.
-type Metric uint32
-
-// ExtendedRoute is a single route that contains the standard tcpip.Route plus
-// additional attributes.
-type ExtendedRoute struct {
- // Route used to build the route table to be fed into the
- // github.com/google/netstack lib.
- Route tcpip.Route
-
- // Metric acts as a tie-breaker when comparing otherwise identical routes.
- Metric Metric
-
- // MetricTracksInterface is true when the metric tracks the metric of the
- // interface for this route. This means when the interface metric changes, so
- // will this route's metric. If false, the metric is static and only changed
- // explicitly by API.
- MetricTracksInterface bool
-
- // Dynamic marks a route as being obtained via DHCP. Such routes are removed
- // from the table when the interface goes down, vs. just being disabled.
- Dynamic bool
-
- // Enabled marks a route as inactive, i.e., its interface is down and packets
- // must not use this route.
- // Disabled routes are omitted when building the route table for the
- // Netstack lib.
- // This flag is used with non-dynamic routes (i.e., statically added routes)
- // to keep them in the table while their interface is down.
- Enabled bool
-}
-
-// Match matches the given address against this route.
-func (er *ExtendedRoute) Match(addr tcpip.Address) bool {
- r := er.Route
- if len(addr) != len(r.Destination) {
- return false
- }
- for i := 0; i < len(r.Destination); i++ {
- if (addr[i] & r.Mask[i]) != r.Destination[i] {
- return false
- }
- }
- return true
-}
-
-func (er *ExtendedRoute) String() string {
- var out strings.Builder
- out.WriteString(fmt.Sprintf(" %v/%v", er.Route.Destination, util.PrefixLength(er.Route.Mask)))
- if len(er.Route.Gateway) > 0 {
- out.WriteString(fmt.Sprintf(" via %v", er.Route.Gateway))
- }
- out.WriteString(fmt.Sprintf(" nic %v", er.Route.NIC))
- if er.MetricTracksInterface {
- out.WriteString(fmt.Sprintf(" metric[if] %v", er.Metric))
- } else {
- out.WriteString(fmt.Sprintf(" metric[static] %v", er.Metric))
- }
- if er.Dynamic {
- out.WriteString(" (dynamic)")
- } else {
- out.WriteString(" (static)")
- }
- if !er.Enabled {
- out.WriteString(" (disabled)")
- }
- out.WriteString("\n")
- return out.String()
-}
-
-// RouteTable implements a sorted list of extended routes that is used to build
-// the Netstack lib route table.
-type RouteTable struct {
- mu struct {
- sync.Mutex
- routes []ExtendedRoute
- }
-}
-
-func (rt *RouteTable) String() string {
- var out strings.Builder
- for _, r := range rt.mu.routes {
- out.WriteString(fmt.Sprintf("%v", &r))
- }
- return out.String()
-}
-
-// For debugging.
-func (rt *RouteTable) Dump() {
- fmt.Printf("Current Route Table:\n%v", rt)
-}
-
-// For testing.
-func (rt *RouteTable) Set(r []ExtendedRoute) {
- rt.mu.Lock()
- defer rt.mu.Unlock()
- rt.mu.routes = append([]ExtendedRoute(nil), r...)
-}
-
-// AddRoute inserts the given route to the table in a sorted fashion. If the
-// route already exists, it simply updates that route's metric, dynamic and
-// enabled fields.
-func (rt *RouteTable) AddRoute(route tcpip.Route, metric Metric, tracksInterface bool, dynamic bool, enabled bool) {
- if debug {
- log.Printf("RouteTable:Adding route %+v with metric:%d, trackIf=%v, dynamic=%v, enabled=%v", route, metric, tracksInterface, dynamic, enabled)
- }
-
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- // First check if the route already exists, and remove it.
- for i, er := range rt.mu.routes {
- if IsSameRoute(route, er.Route) {
- rt.mu.routes = append(rt.mu.routes[:i], rt.mu.routes[i+1:]...)
- break
- }
- }
-
- newEr := ExtendedRoute{
- Route: route,
- Metric: metric,
- MetricTracksInterface: tracksInterface,
- Dynamic: dynamic,
- Enabled: enabled,
- }
-
- // Find the target position for the new route in the table so it remains
- // sorted. Initialized to point to the end of the table.
- targetIdx := len(rt.mu.routes)
- for i, er := range rt.mu.routes {
- if Less(&newEr, &er) {
- targetIdx = i
- break
- }
- }
- // Extend the table by adding the new route at the end, then move it into its
- // proper place.
- rt.mu.routes = append(rt.mu.routes, newEr)
- if targetIdx < len(rt.mu.routes)-1 {
- copy(rt.mu.routes[targetIdx+1:], rt.mu.routes[targetIdx:])
- rt.mu.routes[targetIdx] = newEr
- }
-
- if debug {
- rt.Dump()
- }
-}
-
-// DelRoute removes the given route from the route table.
-func (rt *RouteTable) DelRoute(route tcpip.Route) error {
- if debug {
- log.Printf("RouteTable:Deleting route %+v", route)
- }
-
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- routeDeleted := false
- oldTable := rt.mu.routes
- rt.mu.routes = oldTable[:0]
- for _, er := range oldTable {
- // Match all fields that are non-zero.
- if isSameSubnet(er.Route, route) {
- if route.NIC == 0 || route.NIC == er.Route.NIC {
- if len(route.Gateway) == 0 || route.Gateway == er.Route.Gateway {
- routeDeleted = true
- continue
- }
- }
- }
- // Not matched, remains in the route table.
- rt.mu.routes = append(rt.mu.routes, er)
- }
-
- if !routeDeleted {
- return fmt.Errorf("no such route")
- }
-
- if debug {
- rt.Dump()
- }
- return nil
-}
-
-// GetExtendedRouteTable returns a copy of the current extended route table.
-func (rt *RouteTable) GetExtendedRouteTable() []ExtendedRoute {
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- if debug {
- rt.Dump()
- }
-
- return append([]ExtendedRoute(nil), rt.mu.routes...)
-}
-
-// GetNetstackTable returns the route table to be fed into the
-// github.com/google/netstack lib. It contains all routes except for disabled
-// ones.
-func (rt *RouteTable) GetNetstackTable() []tcpip.Route {
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- t := make([]tcpip.Route, 0, len(rt.mu.routes))
- for _, er := range rt.mu.routes {
- if er.Enabled {
- t = append(t, er.Route)
- }
- }
-
- if debug {
- log.Printf("RouteTable:Netstack route table: %+v", t)
- }
-
- return t
-}
-
-// UpdateMetricByInterface changes the metric for all routes that track a
-// given interface.
-func (rt *RouteTable) UpdateMetricByInterface(nicid tcpip.NICID, metric Metric) {
- if debug {
- log.Printf("RouteTable:Update route table on nic-%d metric change to %d", nicid, metric)
- }
-
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- for i, er := range rt.mu.routes {
- if er.Route.NIC == nicid && er.MetricTracksInterface {
- rt.mu.routes[i].Metric = metric
- }
- }
-
- rt.sortRouteTableLocked()
-
- if debug {
- rt.Dump()
- }
-}
-
-// UpdateRoutesByInterface applies an action to the routes pointing to an interface.
-func (rt *RouteTable) UpdateRoutesByInterface(nicid tcpip.NICID, action Action) {
- if debug {
- log.Printf("RouteTable:Update route table for routes to nic-%d with action:%d", nicid, action)
- }
-
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- oldTable := rt.mu.routes
- rt.mu.routes = oldTable[:0]
- for _, er := range oldTable {
- if er.Route.NIC == nicid {
- switch action {
- case ActionDeleteAll:
- continue // delete
- case ActionDeleteDynamicDisableStatic:
- if er.Dynamic {
- continue // delete
- }
- er.Enabled = false
- case ActionEnableStatic:
- if !er.Dynamic {
- er.Enabled = true
- }
- }
- }
- // Keep.
- rt.mu.routes = append(rt.mu.routes, er)
- }
-
- rt.sortRouteTableLocked()
-
- if debug {
- rt.Dump()
- }
-}
-
-// FindNIC returns the NIC-ID that the given address is routed on. This requires
-// an exact route match, i.e. no default route.
-func (rt *RouteTable) FindNIC(addr tcpip.Address) (tcpip.NICID, error) {
- rt.mu.Lock()
- defer rt.mu.Unlock()
-
- for _, er := range rt.mu.routes {
- // Ignore default routes.
- if util.IsAny(er.Route.Destination) {
- continue
- }
- if er.Match(addr) && er.Route.NIC > 0 {
- return er.Route.NIC, nil
- }
- }
- return 0, fmt.Errorf("cannot find NIC with valid destination route to %v", addr)
-}
-
-func (rt *RouteTable) sortRouteTableLocked() {
- sort.SliceStable(rt.mu.routes, func(i, j int) bool {
- return Less(&rt.mu.routes[i], &rt.mu.routes[j])
- })
-}
-
-// Less compares two routes and returns which one should appear earlier in the
-// route table.
-func Less(ei, ej *ExtendedRoute) bool {
- ri, rj := ei.Route, ej.Route
- // Non-default before default one.
- if util.IsAny(ri.Destination) != util.IsAny(rj.Destination) {
- return !util.IsAny(ri.Destination)
- }
-
- // IPv4 before IPv6 (arbitrary choice).
- if len(ri.Destination) != len(rj.Destination) {
- return len(ri.Destination) == header.IPv4AddressSize
- }
-
- // Longer prefix wins.
- li, lj := util.PrefixLength(ri.Mask), util.PrefixLength(rj.Mask)
- if len(ri.Mask) == len(rj.Mask) && li != lj {
- return li > lj
- }
-
- // Lower metrics wins.
- if ei.Metric != ej.Metric {
- return ei.Metric < ej.Metric
- }
-
- // Everything that matters is the same. At this point we still need a
- // deterministic way to tie-break. First go by destination IPs (lower wins),
- // finally use the NIC.
- riDest, rjDest := []byte(ri.Destination), []byte(rj.Destination)
- for i := 0; i < len(riDest); i++ {
- if riDest[i] != rjDest[i] {
- return riDest[i] < rjDest[i]
- }
- }
-
- // Same prefix and destination IPs (e.g. loopback IPs), use NIC as final
- // tie-breaker.
- return ri.NIC < rj.NIC
-}
-
-func isSameSubnet(a, b tcpip.Route) bool {
- return a.Destination == b.Destination && a.Mask == b.Mask
-}
-
-// IsSameRoute returns true if two routes are the same.
-func IsSameRoute(a, b tcpip.Route) bool {
- if !isSameSubnet(a, b) || a.NIC != b.NIC {
- return false
- }
-
- aHasGW := len(a.Gateway) > 0 && !util.IsAny(a.Gateway)
- bHasGW := len(a.Gateway) > 0 && !util.IsAny(b.Gateway)
- if aHasGW && bHasGW {
- return a.Gateway == b.Gateway
- }
- // either one or both routes have no gateway
- return !aHasGW && !bHasGW
-}
diff --git a/garnet/go/src/netstack/routes/routes_test.go b/garnet/go/src/netstack/routes/routes_test.go
deleted file mode 100644
index efae8e1..0000000
--- a/garnet/go/src/netstack/routes/routes_test.go
+++ /dev/null
@@ -1,602 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package routes_test
-
-import (
- "fmt"
- "net"
- "testing"
-
- "netstack/routes"
- "netstack/util"
-
- "github.com/google/netstack/tcpip"
-)
-
-var testRouteTable = []routes.ExtendedRoute{
- // nic, subnet, gateway, metric, tracksInterface, dynamic, enabled
- createExtendedRoute(1, "127.0.0.1/32", "", 100, true, false, true), // loopback
- createExtendedRoute(4, "192.168.1.0/24", "", 100, true, true, true), // DHCP IP (eth)
- createExtendedRoute(2, "192.168.100.0/24", "", 200, true, true, true), // DHCP IP (wlan)
- createExtendedRoute(3, "10.1.2.0/23", "", 100, true, false, true), // static IP
- createExtendedRoute(2, "110.34.0.0/16", "192.168.100.10", 500, false, false, true), // static route
- createExtendedRoute(1, "::1/128", "", 100, true, false, true), // loopback
- // static route (eth)
- createExtendedRoute(4, "2610:1:22:123:34:faed::/96", "fe80::250:a8ff:9:79", 100, false, false, true),
- createExtendedRoute(4, "2622:0:2200:10::/64", "", 100, true, true, true), // RA (eth)
- createExtendedRoute(4, "0.0.0.0/0", "192.168.1.1", 100, true, true, true), // default (eth)
- createExtendedRoute(2, "0.0.0.0/0", "192.168.100.10", 200, true, true, true), // default (wlan)
- createExtendedRoute(4, "::/0", "fe80::210:6e00:fe11:3265", 100, true, false, true), // default (eth)
-}
-
-func createRoute(nicid tcpip.NICID, subnet string, gateway string) tcpip.Route {
- _, s, _ := net.ParseCIDR(subnet)
- return tcpip.Route{
- Destination: tcpip.Address(s.IP),
- Mask: tcpip.AddressMask(s.Mask),
- Gateway: ipStringToAddress(gateway),
- NIC: nicid,
- }
-}
-
-func createExtendedRoute(nicid tcpip.NICID, subnet string, gateway string, metric routes.Metric, tracksInterface bool, dynamic bool, enabled bool) routes.ExtendedRoute {
- return routes.ExtendedRoute{
- Route: createRoute(nicid, subnet, gateway),
- Metric: metric,
- MetricTracksInterface: tracksInterface,
- Dynamic: dynamic,
- Enabled: enabled,
- }
-}
-
-func ipStringToAddress(ipStr string) tcpip.Address {
- return ipToAddress(net.ParseIP(ipStr))
-}
-
-func ipToAddress(ip net.IP) tcpip.Address {
- if v4 := ip.To4(); v4 != nil {
- return tcpip.Address(v4)
- }
- return tcpip.Address(ip)
-}
-
-func TestExtendedRouteMatch(t *testing.T) {
- for _, tc := range []struct {
- subnet string
- addr string
- want bool
- }{
- {"192.168.10.0/24", "192.168.10.0", true},
- {"192.168.10.0/24", "192.168.10.1", true},
- {"192.168.10.0/24", "192.168.10.10", true},
- {"192.168.10.0/24", "192.168.10.255", true},
- {"192.168.10.0/24", "192.168.11.1", false},
- {"192.168.10.0/24", "192.168.0.1", false},
- {"192.168.10.0/24", "192.167.10.1", false},
- {"192.168.10.0/24", "193.168.10.1", false},
- {"192.168.10.0/24", "0.0.0.0", false},
-
- {"123.220.0.0/14", "123.220.11.22", true},
- {"123.220.0.0/14", "123.221.11.22", true},
- {"123.220.0.0/14", "123.222.11.22", true},
- {"123.220.0.0/14", "123.223.11.22", true},
- {"123.220.0.0/14", "123.224.11.22", false},
-
- {"0.0.0.0/0", "0.0.0.0", true},
- {"0.0.0.0/0", "1.1.1.1", true},
- {"0.0.0.0/0", "255.255.255.255", true},
-
- {"2402:f000:5:8401::/64", "2402:f000:5:8401::", true},
- {"2402:f000:5:8401::/64", "2402:f000:5:8401::1", true},
- {"2402:f000:5:8401::/64", "2402:f000:5:8401:1:12:123::", true},
- {"2402:f000:5:8401::/64", "2402:f000:5:8402::", false},
- {"2402:f000:5:8401::/64", "2402:f000:15:8401::", false},
- {"2402:f000:5:8401::/64", "2402::5:8401::", false},
- {"2402:f000:5:8401::/64", "2400:f000:5:8401::", false},
-
- {"::/0", "::", true},
- {"::/0", "1:1:1:1:1:1:1:1", true},
- {"::/0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", true},
- } {
- t.Run("RouteMatch", func(t *testing.T) {
- er := createExtendedRoute(1, tc.subnet, "", 100, true, true, true)
- addr := ipStringToAddress(tc.addr)
- if got := er.Match(addr); got != tc.want {
- t.Errorf("got match addr %v in subnet %v = %v, want = %v", tc.addr, tc.subnet, got, tc.want)
- }
- })
- }
-}
-
-func TestSortingLess(t *testing.T) {
- for _, tc := range []struct {
- subnet1 string
- metric1 routes.Metric
- nic1 tcpip.NICID
-
- subnet2 string
- metric2 routes.Metric
- nic2 tcpip.NICID
-
- want bool
- }{
- // non-default before default
- {"100.99.24.12/32", 100, 1, "0.0.0.0/0", 100, 1, true},
- {"10.144.0.0/12", 100, 1, "0.0.0.0/0", 100, 2, true},
- {"127.0.0.1/24", 100, 1, "0.0.0.0/0", 100, 1, true},
- {"2511:5f32:4:6:124::2:1/128", 100, 1, "::/0", 100, 1, true},
- {"fe80:ffff:0:1234:5:6::/96", 100, 2, "::/0", 100, 1, true},
- {"::1/128", 100, 2, "::/0", 100, 2, true},
- // IPv4 before IPv6
- {"100.99.24.12/32", 100, 1, "2511:5f32:4:6:124::2/120", 100, 1, true},
- {"100.99.24.12/32", 100, 2, "2605:32::12/128", 100, 1, true},
- {"127.0.0.1/24", 100, 1, "::1/128", 100, 1, true},
- {"0.0.0.0/0", 100, 1, "::/0", 100, 3, true},
- // longer prefix wins
- {"100.99.24.12/32", 100, 2, "100.99.24.12/31", 100, 1, true},
- {"100.99.24.12/32", 100, 1, "10.144.0.0/12", 100, 1, true},
- {"100.99.24.128/25", 100, 5, "127.0.0.1/24", 100, 3, true},
- {"2511:5f32:4:6:124::2:12/128", 100, 1, "2511:5f32:4:6:124::2:12/126", 100, 1, true},
- {"2511:5f32:4:6:124::2:12/128", 100, 1, "2605:32::12/127", 100, 1, true},
- {"fe80:ffff:0:1234:5:6::/96", 100, 2, "2511:5f32:4:6:124::/90", 100, 1, true},
- {"2511:5f32:4:6:124::2:1/128", 100, 1, "::1/120", 100, 2, true},
- // lower metric
- {"100.99.24.12/32", 100, 1, "10.1.21.31/32", 101, 1, true},
- {"100.99.24.12/32", 101, 1, "10.1.21.31/32", 100, 2, false},
- {"100.99.2.0/23", 100, 3, "10.1.22.0/23", 101, 1, true},
- {"100.99.2.0/23", 101, 1, "10.1.22.0/23", 100, 1, false},
- {"2511:5f32:4:6:124::2:1/128", 100, 1, "2605:32::12/128", 101, 1, true},
- {"2511:5f32:4:6:124::2:1/128", 101, 3, "2605:32::12/128", 100, 2, false},
- {"2511:5f32:4:6:124::2:1/96", 100, 1, "fe80:ffff:0:1234:5:6::/96", 101, 4, true},
- {"2511:5f32:4:6:124::2:1/96", 101, 1, "fe80:ffff:0:1234:5:6::/96", 100, 4, false},
- // tie-breaker: destination IPs
- {"10.1.21.31/32", 100, 2, "100.99.24.12/32", 100, 1, true},
- {"100.99.24.12/32", 100, 1, "10.1.21.31/32", 100, 3, false},
- {"2511:5f32:4:6:124::2:1/128", 100, 1, "2605:32::12/128", 100, 1, true},
- {"2605:32::12/128", 100, 1, "2511:5f32:4:6:124::2:1/128", 100, 1, false},
- // tie-breaker: NIC
- {"10.1.21.31/32", 100, 1, "10.1.21.31/32", 100, 2, true},
- {"10.1.21.31/32", 100, 2, "10.1.21.31/32", 100, 1, false},
- {"2511:5f32:4:6:124::2:1/128", 100, 1, "2511:5f32:4:6:124::2:1/128", 100, 2, true},
- {"2511:5f32:4:6:124::2:1/128", 100, 2, "2511:5f32:4:6:124::2:1/128", 100, 1, false},
- } {
- name := fmt.Sprintf("Test-%s@nic%v[m:%v]_<_%s@nic%v[m:%v]", tc.subnet1, tc.nic1, tc.metric1, tc.subnet2, tc.nic2, tc.metric2)
- t.Run(name, func(t *testing.T) {
- e1 := createExtendedRoute(tc.nic1, tc.subnet1, "", tc.metric1, true, true, true)
- e2 := createExtendedRoute(tc.nic2, tc.subnet2, "", tc.metric2, true, true, true)
- if got := routes.Less(&e1, &e2); got != tc.want {
- t.Errorf("got Less(%v, %v) = %v, want = %v", &e1, &e2, got, tc.want)
- }
- // reverse test
- reverseWant := !tc.want
- if got := routes.Less(&e2, &e1); got != reverseWant {
- t.Errorf("Less(%v, %v) = %v, want = %v", e2, e1, got, reverseWant)
- }
- })
- }
-}
-
-func changeByte(b []byte) []byte {
- b[0] = ^b[0]
- return b
-}
-
-func TestIsSameRoute(t *testing.T) {
- gatewaysWithPrefix := []string{"127.0.0.1/32", "0.0.0.0/0", "123.220.3.14/14", "192.168.10.1/24",
- "::1/128", "::/128", "2605:143:32:113::1/64", "fe80:4234:242f:1111:5:243:5:4f/88"}
- nics := []tcpip.NICID{1, 2}
-
- for _, nic1 := range nics {
- t.Run(fmt.Sprintf("nic1=%v", nic1), func(t *testing.T) {
- for _, gp1 := range gatewaysWithPrefix {
- t.Run(fmt.Sprintf("gp1=%v", gp1), func(t *testing.T) {
- ip, s, err := net.ParseCIDR(gp1)
- if err != nil {
- t.Fatalf("net.ParseCIDR(%v) failed", gp1)
- }
- route1 := tcpip.Route{
- Destination: tcpip.Address(ipToAddress(s.IP)),
- Mask: tcpip.AddressMask(s.Mask),
- Gateway: tcpip.Address(ipToAddress(ip)),
- NIC: nic1,
- }
-
- if got := routes.IsSameRoute(route1, route1); got != true {
- t.Fatalf("got IsSameRoute(%v, %v) = %v, want = %v", route1, route1, got, true)
- }
- // Change the NIC
- route2 := route1
- route2.NIC = route1.NIC + 1
- if got := routes.IsSameRoute(route1, route2); got != false {
- t.Errorf("got IsSameRoute(%v, %v) = %v, want = %v", route1, route2, got, false)
- }
- // Change destination.
- route2 = route1
- route2.Destination = tcpip.Address(changeByte([]byte(route2.Destination)))
- if got := routes.IsSameRoute(route1, route2); got != false {
- t.Errorf("got IsSameRoute(%v, %v) = %v, want = %v", route1, route2, got, false)
- }
- // Change gateway.
- route2 = route1
- route2.Gateway = tcpip.Address(changeByte([]byte(route2.Gateway)))
- if got := routes.IsSameRoute(route1, route2); got != false {
- t.Errorf("got IsSameRoute(%v, %v) = %v, want = %v", route1, route2, got, false)
- }
- // Remove gateway if possible
- if !util.IsAny(route1.Gateway) {
- route2 = route1
- route2.Gateway = tcpip.Address("")
- if got := routes.IsSameRoute(route1, route2); got != false {
- t.Errorf("got IsSameRoute(%v, %v) = %v, want = %v", route1, route2, got, false)
- }
- }
- })
- }
- })
- }
-}
-
-func isSameRouteTableImpl(rt1, rt2 []routes.ExtendedRoute, checkAttributes bool) bool {
- if len(rt1) != len(rt2) {
- return false
- }
- for i, r1 := range rt1 {
- r2 := rt2[i]
- if !routes.IsSameRoute(r1.Route, r2.Route) {
- return false
- }
- if checkAttributes && (r1.Metric != r2.Metric || r1.MetricTracksInterface != r2.MetricTracksInterface || r1.Dynamic != r2.Dynamic || r1.Enabled != r2.Enabled) {
- return false
- }
- }
- return true
-}
-
-func isSameRouteTable(rt1, rt2 []routes.ExtendedRoute) bool {
- return isSameRouteTableImpl(rt1, rt2, true /* checkAttributes */)
-}
-
-func isSameRouteTableSkippingAttributes(rt1, rt2 []routes.ExtendedRoute) bool {
- return isSameRouteTableImpl(rt1, rt2, false /* checkAttributes */)
-}
-
-func TestAddRoute(t *testing.T) {
- for _, tc := range []struct {
- name string
- order []int
- }{
- // different orders
- {"Add1", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
- {"Add2", []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
- {"Add3", []int{5, 3, 9, 2, 6, 0, 7, 10, 1, 4, 8}},
- {"Add4", []int{6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 0}},
-
- // different orders and duplicates
- {"Add5", []int{0, 0, 1, 2, 3, 4, 2, 5, 6, 7, 1, 8, 9, 10, 0}},
- {"Add6", []int{10, 9, 8, 4, 7, 6, 5, 2, 4, 3, 2, 1, 0, 5, 5}},
- {"Add7", []int{5, 3, 9, 2, 6, 0, 7, 10, 10, 1, 3, 4, 8}},
- {"Add8", []int{6, 6, 6, 5, 7, 4, 8, 3, 9, 9, 2, 7, 10, 1, 0}},
- } {
- t.Run(tc.name, func(t *testing.T) {
- // Create route table by adding all routes in the given order.
- tb := routes.RouteTable{}
- for _, j := range tc.order {
- r := testRouteTable[j]
- tb.AddRoute(r.Route, r.Metric, r.MetricTracksInterface, r.Dynamic, r.Enabled)
- }
- tableWanted := testRouteTable
- tableGot := tb.GetExtendedRouteTable()
- if len(tableGot) != len(tableWanted) {
- t.Fatalf("got len(table) = %v, want len(table) = %v", len(tableGot), len(tableWanted))
- }
- if !isSameRouteTable(tableGot, tableWanted) {
- t.Errorf("got\n%v, want\n%v", tableGot, tableWanted)
- }
- })
- }
-
- // Adding a route that already exists but with different dynamic/enabled
- // attributes will just overwrite the entry with the new attributes. The
- // position in the table stays the same.
- t.Run("Changing dynamic/enabled", func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
- for i, r := range testRouteTable {
- r.Dynamic = !r.Dynamic
- tb.AddRoute(r.Route, r.Metric, r.MetricTracksInterface, r.Dynamic, r.Enabled)
- tableWanted := testRouteTable
- tableGot := tb.GetExtendedRouteTable()
- if tableGot[i].Dynamic != r.Dynamic {
- t.Errorf("got tableGot[%d].Dynamic = %v, want %v", i, tableGot[i].Dynamic, r.Dynamic)
- }
- if !isSameRouteTableSkippingAttributes(tableGot, tableWanted) {
- t.Errorf("got\n%v, want\n%v", tableGot, tableWanted)
- }
-
- r.Enabled = !r.Enabled
- tb.AddRoute(r.Route, r.Metric, r.MetricTracksInterface, r.Dynamic, r.Enabled)
- tableGot = tb.GetExtendedRouteTable()
- if tableGot[i].Enabled != r.Enabled {
- t.Errorf("got tableGot[%d].Enabled = %v, want %v", i, tableGot[i].Enabled, r.Enabled)
- }
- if !isSameRouteTableSkippingAttributes(tableGot, tableWanted) {
- t.Errorf("got\n%v, want\n%v", tableGot, tableWanted)
- }
- }
- })
-
- // The metric is used as a tie-breaker when routes have the same prefix length
- t.Run("Changing metric", func(t *testing.T) {
- r0 := createRoute(1, "0.0.0.0/0", "192.168.1.1")
- r1 := createRoute(2, "0.0.0.0/0", "192.168.100.10")
-
- // 1.test - r0 gets lower metric.
- tb := routes.RouteTable{}
- tb.AddRoute(r0, 100, true, true, true)
- tb.AddRoute(r1, 200, true, true, true)
- tableGot := tb.GetExtendedRouteTable()
- if !routes.IsSameRoute(r0, tableGot[0].Route) || !routes.IsSameRoute(r1, tableGot[1].Route) {
- t.Errorf("got %v, %v, want %v, %v", tableGot[0].Route, tableGot[1].Route, r0, r1)
- }
-
- // 2.test - r1 gets lower metric.
- tb = routes.RouteTable{}
- tb.AddRoute(r0, 200, true, true, true)
- tb.AddRoute(r1, 100, true, true, true)
- tableGot = tb.GetExtendedRouteTable()
- if !routes.IsSameRoute(r0, tableGot[1].Route) || !routes.IsSameRoute(r1, tableGot[0].Route) {
- t.Errorf("got %v, %v, want %v, %v", tableGot[0].Route, tableGot[1].Route, r1, r0)
- }
- })
-}
-
-func TestDelRoute(t *testing.T) {
- for _, tc := range []struct {
- name string
- order []int
- }{
- {"Del1", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
- {"Del2", []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
- {"Del3", []int{6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 0}},
- {"Del4", []int{0}},
- {"Del5", []int{1}},
- {"Del6", []int{9}},
- {"Del7", []int{0, 0, 1, 1, 5, 5, 9, 9, 10, 10}},
- {"Del8", []int{5, 8, 5, 0, 1, 9, 1, 5}},
- } {
- t.Run(tc.name, func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
- validRoutes := make([]bool, len(testRouteTable))
- for i, _ := range validRoutes {
- validRoutes[i] = true
- }
- for _, d := range tc.order {
- toDel := testRouteTable[d]
- tb.DelRoute(toDel.Route)
- validRoutes[d] = false
- }
- tableGot := tb.GetExtendedRouteTable()
- tableWant := []routes.ExtendedRoute{}
- for i, valid := range validRoutes {
- if valid {
- tableWant = append(tableWant, testRouteTable[i])
- }
- }
- if !isSameRouteTable(tableGot, tableWant) {
- t.Errorf("got\n%v, want\n%v", tableGot, tableWant)
- }
- })
- }
-}
-
-func TestUpdateMetricByInterface(t *testing.T) {
- // Updating the metric for the an interface updates the metric for all routes
- // that track that interface.
- for nicid := tcpip.NICID(1); nicid <= 4; nicid++ {
- t.Run(fmt.Sprintf("Change-NIC-%d-metric-updates-route-metric", nicid), func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
- newMetric := routes.Metric(1000 + nicid)
- // Verify existing table does not use the new metric yet.
- tableGot := tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if r.Metric == newMetric {
- t.Fatalf("Error: r.Metric said to invalid value before test start")
- }
- }
-
- tb.UpdateMetricByInterface(nicid, newMetric)
-
- tableGot = tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if r.Route.NIC != nicid {
- continue
- }
- if !r.MetricTracksInterface && r.Metric == newMetric {
- t.Errorf("got MetricTracksInterface==false && Metric=%v, want metric!=%v", r.Metric, newMetric)
- }
- if r.MetricTracksInterface && r.Metric != newMetric {
- t.Errorf("got MetricTracksInterface==true && Metric=%v, want metric=%v", r.Metric, newMetric)
- }
- }
- })
- }
-
- // A metric change should trigger a re-sort of the routing table.
- t.Run(fmt.Sprint("Change-metric-resorts-table"), func(t *testing.T) {
- r0 := createRoute(0, "0.0.0.0/0", "192.168.1.1")
- r1 := createRoute(1, "0.0.0.0/0", "192.168.100.10")
-
- // Initially r0 has lower metric and is ahead in the table.
- tb := routes.RouteTable{}
- tb.AddRoute(r0, 100, true, true, true)
- tb.AddRoute(r1, 200, true, true, true)
- tableGot := tb.GetExtendedRouteTable()
- if !routes.IsSameRoute(r0, tableGot[0].Route) || !routes.IsSameRoute(r1, tableGot[1].Route) {
- t.Errorf("got %v, %v, want %v, %v", tableGot[0].Route, tableGot[1].Route, r0, r1)
- }
-
- // Lowering nic1's metric should be reflected in r1's metric and promote it
- // in the route table.
- tb.UpdateMetricByInterface(1, 50)
- tableGot = tb.GetExtendedRouteTable()
- if !routes.IsSameRoute(r0, tableGot[1].Route) || !routes.IsSameRoute(r1, tableGot[0].Route) {
- t.Errorf("got %v, %v, want %v, %v", tableGot[0].Route, tableGot[1].Route, r1, r0)
- }
- })
-}
-
-func TestUpdateRoutesByInterface(t *testing.T) {
- for nicid := tcpip.NICID(1); nicid <= 4; nicid++ {
- // Test the normal case where on DOWN netstack removes dynamic routes and
- // disables static ones (ActionDeleteDynamicDisableStatic), and on up
- // it re-enables static routes (ActionEnableStatic).
- t.Run(fmt.Sprintf("Down-Up_NIC-%d", nicid), func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
- tableGot := tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if !r.Enabled {
- t.Errorf("Error: Route %v is disabled before test start", r)
- }
- }
-
- // Down -> Remove dynamic routes and disable static ones.
- tb.UpdateRoutesByInterface(nicid, routes.ActionDeleteDynamicDisableStatic)
-
- // Verify all dynamic routes to this NIC are gone, and static ones are
- // disabled.
- tableGot = tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if r.Route.NIC != nicid {
- continue
- }
- if r.Enabled {
- t.Errorf("got %v = enabled, want = disabled", r)
- }
- if r.Dynamic {
- t.Errorf("got dynamic %v, want it removed", r.Metric)
- }
- }
-
- // Up -> Re-enable static routes.
- tb.UpdateRoutesByInterface(nicid, routes.ActionEnableStatic)
-
- // Verify dynamic routes to this NIC are still gone, and static ones are
- // enabled.
- tableGot = tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if r.Route.NIC != nicid {
- continue
- }
- if !r.Enabled {
- t.Errorf("got %v = enabled, want = disabled", r)
- }
- if r.Dynamic {
- t.Errorf("got dynamic %v, want it removed", r.Metric)
- }
- }
- })
-
- // Test the special case where the interface is removed and in response all
- // routes to this interface are removed (ActionDeleteAll).
- t.Run(fmt.Sprintf("Remove_NIC-%d", nicid), func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
- tableGot := tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if !r.Enabled {
- t.Errorf("Error: Route %v is disabled before test start", r)
- }
- }
-
- // Remove all routes to nicid.
- tb.UpdateRoutesByInterface(nicid, routes.ActionDeleteAll)
-
- // Verify all routes to this NIC are gone.
- tableGot = tb.GetExtendedRouteTable()
- for _, r := range tableGot {
- if r.Route.NIC == nicid {
- t.Errorf("got route %v pointing to NIC-%d, want none", r, nicid)
- }
- }
- })
- }
-}
-
-func TestGetNetstackTable(t *testing.T) {
- for _, tc := range []struct {
- name string
- disabled []int
- }{
- {"GetNsTable1", []int{}},
- {"GetNsTable2", []int{0}},
- {"GetNsTable3", []int{10}},
- {"GetNsTable4", []int{1}},
- {"GetNsTable5", []int{9}},
- {"GetNsTable6", []int{3, 5, 8}},
- {"GetNsTable7", []int{0, 1, 5, 6, 8, 9, 10}},
- {"GetNsTable8", []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
- } {
- t.Run(tc.name, func(t *testing.T) {
- // We have no way to directly disable routes in the route table, but we
- // can use the Set() command to set a table with pre-disabled routes.
- testRouteTable2 := make([]routes.ExtendedRoute, len(testRouteTable))
- copy(testRouteTable2, testRouteTable)
- // Disable a few routes.
- for _, i := range tc.disabled {
- testRouteTable2[i].Enabled = false
- }
- tb := routes.RouteTable{}
- tb.Set(testRouteTable2)
-
- tableGot := tb.GetNetstackTable()
-
- // Verify no disabled routes are in the Netstack table we got.
- i := 0
- for _, r := range testRouteTable2 {
- if r.Enabled {
- if !routes.IsSameRoute(tableGot[i], r.Route) {
- t.Errorf("got = %v, want = %v", tableGot[i], r.Route)
- }
- i += 1
- }
- }
- })
- }
-}
-
-func TestFindNIC(t *testing.T) {
- for _, tc := range []struct {
- name string
- addr string
- nicWanted tcpip.NICID // 0 means not found
- }{
- {"FindNic1", "127.0.0.1", 1},
- {"FindNic2", "127.0.0.0", 0},
- {"FindNic3", "192.168.1.234", 4},
- {"FindNic4", "192.168.1.1", 4},
- {"FindNic5", "192.168.2.1", 0},
- {"FindNic6", "192.168.100.1", 2},
- {"FindNic7", "192.168.100.10", 2},
- {"FindNic8", "192.168.101.10", 0},
- {"FindNic9", "10.1.2.1", 3},
- {"FindNic10", "10.1.3.1", 3},
- {"FindNic11", "10.1.4.1", 0},
- } {
- t.Run(tc.name, func(t *testing.T) {
- tb := routes.RouteTable{}
- tb.Set(testRouteTable)
-
- nicGot, err := tb.FindNIC(ipStringToAddress(tc.addr))
- if err != nil && tc.nicWanted > 0 {
- t.Errorf("got nic = <unknown>, want = %v", tc.nicWanted)
- } else if err == nil && tc.nicWanted != nicGot {
- t.Errorf("got nic = %d, want = %v", nicGot, tc.nicWanted)
- }
- })
- }
-}
diff --git a/garnet/go/src/netstack/util/parse.go b/garnet/go/src/netstack/util/parse.go
index 68a6222..b46695d 100644
--- a/garnet/go/src/netstack/util/parse.go
+++ b/garnet/go/src/netstack/util/parse.go
@@ -11,19 +11,6 @@
"github.com/google/netstack/tcpip"
)
-func IsAny(a tcpip.Address) bool {
- // An empty address is not the same as ANY.
- if len(a) == 0 {
- return false
- }
- for _, n := range a {
- if n != 0 {
- return false
- }
- }
- return true
-}
-
func ApplyMask(addr tcpip.Address, mask tcpip.AddressMask) tcpip.Address {
return tcpip.Address(net.IP(addr).Mask(net.IPMask(mask)))
}
@@ -32,11 +19,6 @@
return tcpip.AddressMask(net.CIDRMask(ones, bits))
}
-func PrefixLength(mask tcpip.AddressMask) int {
- bits, _ := net.IPMask(mask).Size()
- return bits
-}
-
func ipToAddress(ip net.IP) tcpip.Address {
if v4 := ip.To4(); v4 != nil {
return tcpip.Address(v4)
diff --git a/garnet/go/src/netstack/util/parse_test.go b/garnet/go/src/netstack/util/parse_test.go
index 6923cdcd..b801ad6 100644
--- a/garnet/go/src/netstack/util/parse_test.go
+++ b/garnet/go/src/netstack/util/parse_test.go
@@ -68,70 +68,3 @@
}
}
}
-
-func TestIsAny(t *testing.T) {
- for _, tc := range []struct {
- name string
- addr tcpip.Address
- want bool
- }{
- {"IPv4-Empty", "", false},
- {"IPv4-Zero", "\x00\x00\x00\x00", true},
- {"IPv4-Loopback", "\x7f\x00\x00\x01", false},
- {"IPv4-Broadcast", "\xff\xff\xff\xff", false},
- {"IPv4-Regular1", "\x00\x00\x00\x01", false},
- {"IPv4-Regular2", "\x00\x00\x01\x00", false},
- {"IPv4-Regular3", "\x00\x01\x00\x00", false},
- {"IPv4-Regular4", "\x01\x00\x00\x00", false},
- {"IPv4-Regular5", "\x01\x01\x01\x01", false},
- {"IPv4-Regular6", "\x11\x22\x33\x44", false},
- {"IPv6-Empty", "", false},
- {"IPv6-Zero", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", true},
- {"IPv6-Loopback", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", false},
- {"IPv6-Broadcast", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", false},
- {"IPv6-Regular1", "\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", false},
- {"IPv6-Regular2", "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00", false},
- {"IPv6-Regular3", "\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00", false},
- {"IPv6-Regular4", "\x00\xaa\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", false},
- {"IPv6-Regular5", "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", false},
- } {
- t.Run(tc.name, func(t *testing.T) {
- if got := util.IsAny(tc.addr); got != tc.want {
- t.Fatalf("IsAny(%v) = %v, want = %v", tc.addr, got, tc.want)
- }
- })
- }
-}
-
-func TestPrefixLength(t *testing.T) {
- for _, tc := range []struct {
- name string
- mask tcpip.AddressMask
- want int
- }{
- {"IPv4-Empty", "", 0},
- {"IPv4-0", "\x00\x00\x00\x00", 0},
- {"IPv4-3", "\xe0\x00\x00\x00", 3},
- {"IPv4-7", "\xfe\x00\x00\x00", 7},
- {"IPv4-8", "\xff\x00\x00\x00", 8},
- {"IPv4-12", "\xff\xf0\x00\x00", 12},
- {"IPv4-16", "\xff\xff\x00\x00", 16},
- {"IPv4-24", "\xff\xff\xff\x00", 24},
- {"IPv4-29", "\xff\xff\xff\xfc", 30},
- {"IPv4-32", "\xff\xff\xff\xff", 32},
- {"IPv6-Empty", "", 0},
- {"IPv6-0", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 0},
- {"IPv6-5", "\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 5},
- {"IPv6-8", "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 8},
- {"IPv6-22", "\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 22},
- {"IPv6-73", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00", 73},
- {"IPv6-123", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0", 123},
- {"IPv6-128", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 128},
- } {
- t.Run(tc.name, func(t *testing.T) {
- if got := util.PrefixLength(tc.mask); got != tc.want {
- t.Fatalf("PrefixLength(%v) = %v, want = %v", tc.mask, got, tc.want)
- }
- })
- }
-}
diff --git a/garnet/packages/tests/netstack b/garnet/packages/tests/netstack
index 39fd20b..3540a69 100644
--- a/garnet/packages/tests/netstack
+++ b/garnet/packages/tests/netstack
@@ -13,7 +13,6 @@
"host_tests": [
"//garnet/go/src/netstack/dns:netstack_dns_test",
"//garnet/go/src/netstack/link/bridge:netstack_link_bridge_test",
- "//garnet/go/src/netstack/routes:netstack_routes_test",
"//garnet/go/src/netstack/util:netstack_util_test"
]
}
diff --git a/sdk/fidl/fuchsia.netstack/netstack.fidl b/sdk/fidl/fuchsia.netstack/netstack.fidl
index de29872..de994a2 100644
--- a/sdk/fidl/fuchsia.netstack/netstack.fidl
+++ b/sdk/fidl/fuchsia.netstack/netstack.fidl
@@ -111,23 +111,6 @@
vector<uint8> hwaddr;
};
-// New version that includes a metric value.
-// TODO(NET-2078): Move this to NetInterface once Chromium stops using
-// netstack.fidl.
-struct NetInterface2 {
- uint32 id;
- uint32 flags;
- uint32 features;
- uint32 configuration;
- uint32 metric;
- string name;
- fuchsia.net.IpAddress addr;
- fuchsia.net.IpAddress netmask;
- fuchsia.net.IpAddress broadaddr;
- vector<fuchsia.net.Subnet> ipv6addrs;
- vector<uint8> hwaddr;
-};
-
// Flags for NetInterface.flags.
const uint32 NetInterfaceFlagUp = 0x01; // Set if the interface is up.
const uint32 NetInterfaceFlagDhcp = 0x02; // Set if DHCP is enabled.
@@ -139,17 +122,6 @@
uint32 nicid;
};
-// New version that includes a metric value.
-// TODO(NET-2078): Move this to NetInterface once Chromium stops using
-// netstack.fidl.
-struct RouteTableEntry2 {
- fuchsia.net.IpAddress destination;
- fuchsia.net.IpAddress netmask;
- fuchsia.net.IpAddress? gateway;
- uint32 nicid;
- uint32 metric;
-};
-
struct SocketAddress {
fuchsia.net.IpAddress addr;
uint16 port;
@@ -169,15 +141,13 @@
// Returns the list of registered network interfaces.
GetInterfaces() -> (vector<NetInterface> interfaces);
- GetInterfaces2() -> (vector<NetInterface2> interfaces);
// DEPRECATED: see devicesettings.fidl
// Returns the netstack's node name.
// 5: GetNodeName() -> (string node_name);
- // Returns current route table.
+ // Don't use this for read-modify-write. Use StartRouteTableTransaction instead.
GetRouteTable() -> (vector<RouteTableEntry> rt);
- GetRouteTable2() -> (vector<RouteTableEntry2> rt);
// TODO (porce): Separate interfaces.
GetStats(uint32 nicid) -> (NetInterfaceStats stats);
@@ -188,6 +158,9 @@
// Sets the status (up or down) for the interface with the given nicid.
SetInterfaceStatus(uint32 nicid, bool enabled);
+ // DEPRECATED: Use StartRouteTableTransaction and SetRouteTable from there.
+ // 9: SetRouteTable(vector<RouteTableEntry> rt);
+
// Sets the address for the interface with the given nicid.
// Masks off addr.PrefixLen bits from addr.Addr to set the subnet.
SetInterfaceAddress(uint32 nicid, fuchsia.net.IpAddress addr, uint8 prefixLen) -> (NetErr result);
@@ -196,9 +169,6 @@
// Masks off addr.PrefixLen bits from addr.Addr to set the subnet.
RemoveInterfaceAddress(uint32 nicid, fuchsia.net.IpAddress addr, uint8 prefixLen) -> (NetErr result);
- // Sets the route metric for the interface with the given nicid.
- SetInterfaceMetric(uint32 nicid, uint32 metric) -> (NetErr result);
-
SetDhcpClientStatus(uint32 nicid, bool enabled) -> (NetErr result);
BridgeInterfaces(vector<uint32> nicids) -> (NetErr result);
@@ -213,11 +183,15 @@
StartRouteTableTransaction(request<RouteTableTransaction> routeTableTransaction) -> (zx.status status);
-> OnInterfacesChanged(vector<NetInterface> interfaces);
- -> OnInterfacesChanged2(vector<NetInterface2> interfaces);
};
+// When Commit is called, the most recent SetRouteTable will be
+// committed to the route tables. Commit may be called multiple times.
[Discoverable]
interface RouteTableTransaction {
- AddRoute(RouteTableEntry2 r) -> (zx.status status);
- DelRoute(RouteTableEntry2 r) -> (zx.status status);
+ GetRouteTable() -> (vector<RouteTableEntry> rt);
+
+ SetRouteTable(vector<RouteTableEntry> rt);
+
+ Commit() -> (zx.status status);
};