OffloadUtils: move existing ethernet device check to isEthernet() helper
Preparation for tethering bpf offload
Test: manual clatd test
1. Connect to IPv6-Only WiFi hotspot
2. Browse 172.217.0.46 (google.com) successfully
3. Disconnect from WiFi
Repeat the above steps three times.
Change-Id: Ib2fdc644c6048acaacf51c46c6960e8cd6cbc445
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index 0668de3..0e8fdb8 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -19,7 +19,6 @@
#include <arpa/inet.h>
#include <errno.h>
-#include <linux/if_arp.h>
#include <linux/if_tun.h>
#include <linux/ioctl.h>
#include <net/if.h>
@@ -256,39 +255,24 @@
void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
if (mClatEbpfMode == ClatEbpfDisabled) return;
- int rv = hardwareAddressType(tracker.iface);
- if (rv < 0) {
- ALOGE("hardwareAddressType(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
- strerror(-rv));
+ auto isEthernet = android::net::isEthernet(tracker.iface);
+ if (!isEthernet.ok()) {
+ ALOGE("isEthernet(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
+ isEthernet.error().message().c_str());
return;
}
- bool isEthernet;
- switch (rv) {
- case ARPHRD_ETHER:
- isEthernet = true;
- break;
- case ARPHRD_RAWIP: // in Linux 4.14+ rmnet support was upstreamed and this is 519
- case 530: // this is ARPHRD_RAWIP on some Android 4.9 kernels with rmnet
- isEthernet = false;
- break;
- default:
- ALOGE("hardwareAddressType(%s[%d]) returned unknown type %d.", tracker.iface,
- tracker.ifIndex, rv);
- return;
- }
-
// This program will be attached to the v4-* interface which is a TUN and thus always rawip.
- rv = getClatEgressProgFd(RAWIP);
+ int rv = getClatEgressProgFd(RAWIP);
if (rv < 0) {
ALOGE("getClatEgressProgFd(RAWIP) failure: %s", strerror(-rv));
return;
}
unique_fd txRawIpProgFd(rv);
- rv = getClatIngressProgFd(isEthernet);
+ rv = getClatIngressProgFd(isEthernet.value());
if (rv < 0) {
- ALOGE("getClatIngressProgFd(%d) failure: %s", isEthernet, strerror(-rv));
+ ALOGE("getClatIngressProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
return;
}
unique_fd rxProgFd(rv);
@@ -301,7 +285,7 @@
.oif = tracker.ifIndex,
.local6 = tracker.v6,
.pfx96 = tracker.pfx96,
- .oifIsEthernet = isEthernet,
+ .oifIsEthernet = isEthernet.value(),
};
auto ret = mClatEgressMap.writeValue(txKey, txValue, BPF_ANY);
@@ -373,14 +357,14 @@
return;
}
- rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet);
+ rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
if (rv) {
if ((rv == -ENOENT) && (mClatEbpfMode == ClatEbpfMaybe)) {
ALOGI("tcFilterAddDevIngressClatIpv6(%d[%s], %d): %s", tracker.ifIndex, tracker.iface,
- isEthernet, strerror(-rv));
+ isEthernet.value(), strerror(-rv));
} else {
ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
- tracker.iface, isEthernet, strerror(-rv));
+ tracker.iface, isEthernet.value(), strerror(-rv));
}
rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
if (rv) {
diff --git a/server/OffloadUtils.cpp b/server/OffloadUtils.cpp
index b374722..53665f6 100644
--- a/server/OffloadUtils.cpp
+++ b/server/OffloadUtils.cpp
@@ -18,6 +18,7 @@
#include <arpa/inet.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/netlink.h>
#include <linux/pkt_cls.h>
#include <linux/pkt_sched.h>
@@ -60,6 +61,25 @@
return ifr.ifr_hwaddr.sa_family;
}
+base::Result<bool> isEthernet(const std::string& interface) {
+ int rv = hardwareAddressType(interface);
+ if (rv < 0) {
+ errno = -rv;
+ return ErrnoErrorf("Get hardware address type of interface {} failed", interface);
+ }
+
+ switch (rv) {
+ case ARPHRD_ETHER:
+ return true;
+ case ARPHRD_RAWIP: // in Linux 4.14+ rmnet support was upstreamed and this is 519
+ case 530: // this is ARPHRD_RAWIP on some Android 4.9 kernels with rmnet
+ return false;
+ default:
+ errno = EAFNOSUPPORT; // Address family not supported
+ return ErrnoErrorf("Unknown hardware address type {} on interface {}", rv, interface);
+ }
+}
+
// TODO: use //system/netd/server/NetlinkCommands.cpp:openNetlinkSocket(protocol)
// and //system/netd/server/SockDiag.cpp:checkError(fd)
static int sendAndProcessNetlinkResponse(const void* req, int len) {
diff --git a/server/OffloadUtils.h b/server/OffloadUtils.h
index b44ffdf..cdb0d33 100644
--- a/server/OffloadUtils.h
+++ b/server/OffloadUtils.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android-base/result.h>
#include <errno.h>
#include <linux/if_ether.h>
#include <linux/rtnetlink.h>
@@ -28,9 +29,6 @@
namespace android {
namespace net {
-// this returns an ARPHRD_* constant or a -errno
-int hardwareAddressType(const std::string& interface);
-
// For better code clarity - do not change values - used for booleans like
// with_ethernet_header or isEthernet.
constexpr bool RAWIP = false;
@@ -44,6 +42,11 @@
constexpr uint16_t PRIO_CLAT = 1;
constexpr uint16_t PRIO_TETHER = 2;
+// this returns an ARPHRD_* constant or a -errno
+int hardwareAddressType(const std::string& interface);
+
+base::Result<bool> isEthernet(const std::string& interface);
+
inline int getClatEgressMapFd(void) {
const int fd = bpf::bpfFdGet(CLAT_EGRESS_MAP_PATH, 0);
return (fd == -1) ? -errno : fd;
diff --git a/server/OffloadUtilsTest.cpp b/server/OffloadUtilsTest.cpp
index b404bc8..a2c3982 100644
--- a/server/OffloadUtilsTest.cpp
+++ b/server/OffloadUtilsTest.cpp
@@ -65,6 +65,39 @@
ASSERT_EQ(ARPHRD_RAWIP, type);
}
+TEST_F(OffloadUtilsTest, IsEthernetOfNonExistingIf) {
+ auto res = isEthernet("not_existing_if");
+ ASSERT_FALSE(res.ok());
+ ASSERT_EQ(ENODEV, res.error().code());
+}
+
+TEST_F(OffloadUtilsTest, IsEthernetOfLoopback) {
+ auto res = isEthernet("lo");
+ ASSERT_FALSE(res.ok());
+ ASSERT_EQ(EAFNOSUPPORT, res.error().code());
+}
+
+// If wireless 'wlan0' interface exists it should be Ethernet.
+// See also HardwareAddressTypeOfWireless.
+TEST_F(OffloadUtilsTest, IsEthernetOfWireless) {
+ auto res = isEthernet("wlan0");
+ if (!res.ok() && res.error().code() == ENODEV) return;
+
+ ASSERT_RESULT_OK(res);
+ ASSERT_TRUE(res.value());
+}
+
+// If cellular 'rmnet_data0' interface exists it should
+// *probably* not be Ethernet and instead be RawIp.
+// See also HardwareAddressTypeOfCellular.
+TEST_F(OffloadUtilsTest, IsEthernetOfCellular) {
+ auto res = isEthernet("rmnet_data0");
+ if (!res.ok() && res.error().code() == ENODEV) return;
+
+ ASSERT_RESULT_OK(res);
+ ASSERT_FALSE(res.value());
+}
+
TEST_F(OffloadUtilsTest, GetClatEgressMapFd) {
SKIP_IF_BPF_NOT_SUPPORTED;