rename ClatUtils to OffloadUtils

Generated via:
  mv server/ClatUtils.h       server/OffloadUtils.h
  mv server/ClatUtils.cpp     server/OffloadUtils.cpp
  mv server/ClatUtilsTest.cpp server/OffloadUtilsTest.cpp
  sed -i -r 's@ClatUtils@OffloadUtils@g' server/OffloadUtils.cpp
  sed -i -r 's@ClatUtils@OffloadUtils@g' server/OffloadUtilsTest.cpp
  sed -i -r 's@ClatUtils@OffloadUtils@g' server/Android.bp
  sed -i -r 's@ClatUtils@OffloadUtils@g' server/ClatdController.cpp

+ sort Android.bp
+ sort include order in server/ClatdController.cpp

Test: build, atest
  'find | egrep ClatUtils' and 'git grep ClatUtils' come up empty
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I33dbfab8241fd378d1d6ab44843bdae17196e2d1
diff --git a/server/OffloadUtilsTest.cpp b/server/OffloadUtilsTest.cpp
new file mode 100644
index 0000000..ed39c2e
--- /dev/null
+++ b/server/OffloadUtilsTest.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OffloadUtilsTest.cpp - unit tests for OffloadUtils.cpp
+ */
+
+#include <gtest/gtest.h>
+
+#include "OffloadUtils.h"
+
+#include <linux/if_arp.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include "bpf/BpfUtils.h"
+#include "netdbpf/bpf_shared.h"
+
+namespace android {
+namespace net {
+
+class OffloadUtilsTest : public ::testing::Test {
+  public:
+    void SetUp() {}
+};
+
+TEST_F(OffloadUtilsTest, HardwareAddressTypeOfNonExistingIf) {
+    ASSERT_EQ(-ENODEV, hardwareAddressType("not_existing_if"));
+}
+
+TEST_F(OffloadUtilsTest, HardwareAddressTypeOfLoopback) {
+    ASSERT_EQ(ARPHRD_LOOPBACK, hardwareAddressType("lo"));
+}
+
+// If wireless 'wlan0' interface exists it should be Ethernet.
+TEST_F(OffloadUtilsTest, HardwareAddressTypeOfWireless) {
+    int type = hardwareAddressType("wlan0");
+    if (type == -ENODEV) return;
+
+    ASSERT_EQ(ARPHRD_ETHER, type);
+}
+
+// If cellular 'rmnet_data0' interface exists it should
+// *probably* not be Ethernet and instead be RawIp.
+TEST_F(OffloadUtilsTest, HardwareAddressTypeOfCellular) {
+    int type = hardwareAddressType("rmnet_data0");
+    if (type == -ENODEV) return;
+
+    ASSERT_NE(ARPHRD_ETHER, type);
+
+    // ARPHRD_RAWIP is 530 on some pre-4.14 Qualcomm devices.
+    if (type == 530) return;
+
+    ASSERT_EQ(ARPHRD_RAWIP, type);
+}
+
+TEST_F(OffloadUtilsTest, GetClatEgressMapFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatEgressMapFd();
+    ASSERT_LE(3, fd);  // 0,1,2 - stdin/out/err, thus 3 <= fd
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetClatEgressRawIpProgFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatEgressProgFd(false);
+    ASSERT_LE(3, fd);
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetClatEgressEtherProgFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatEgressProgFd(true);
+    ASSERT_LE(3, fd);
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetClatIngressMapFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatIngressMapFd();
+    ASSERT_LE(3, fd);  // 0,1,2 - stdin/out/err, thus 3 <= fd
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetClatIngressRawIpProgFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatIngressProgFd(false);
+    ASSERT_LE(3, fd);
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetClatIngressEtherProgFd) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
+    int fd = getClatIngressProgFd(true);
+    ASSERT_LE(3, fd);
+    close(fd);
+}
+
+TEST_F(OffloadUtilsTest, TryOpeningNetlinkSocket) {
+    int fd = openNetlinkSocket();
+    ASSERT_LE(3, fd);
+    close(fd);
+}
+
+// The SKIP_IF_BPF_NOT_SUPPORTED macro is effectively a check for 4.9+ kernel
+// combined with a launched on P device.  Ie. it's a test for 4.9-P or better.
+
+// NET_SCH_INGRESS is only enabled starting with 4.9-Q and as such we need
+// a separate way to test for this...
+int doKernelSupportsNetSchIngress(void) {
+    // NOLINTNEXTLINE(cert-env33-c)
+    return system("zcat /proc/config.gz | egrep -q '^CONFIG_NET_SCH_INGRESS=[my]$'");
+}
+
+// NET_CLS_BPF is only enabled starting with 4.9-Q...
+int doKernelSupportsNetClsBpf(void) {
+    // NOLINTNEXTLINE(cert-env33-c)
+    return system("zcat /proc/config.gz | egrep -q '^CONFIG_NET_CLS_BPF=[my]$'");
+}
+
+// Make sure the above functions actually execute correctly rather than failing
+// due to missing binary or execution failure...
+TEST_F(OffloadUtilsTest, KernelSupportsNetFuncs) {
+    // Make sure the file is present and readable and decompressable.
+    // NOLINTNEXTLINE(cert-env33-c)
+    ASSERT_EQ(W_EXITCODE(0, 0), system("zcat /proc/config.gz > /dev/null"));
+
+    int v = doKernelSupportsNetSchIngress();
+    int w = doKernelSupportsNetClsBpf();
+
+    // They should always either return 0 (match) or 1 (no match),
+    // anything else is some sort of exec/environment/etc failure.
+    if (v != W_EXITCODE(1, 0)) ASSERT_EQ(v, W_EXITCODE(0, 0));
+    if (w != W_EXITCODE(1, 0)) ASSERT_EQ(w, W_EXITCODE(0, 0));
+}
+
+// True iff CONFIG_NET_SCH_INGRESS is enabled in /proc/config.gz
+bool kernelSupportsNetSchIngress(void) {
+    return doKernelSupportsNetSchIngress() == W_EXITCODE(0, 0);
+}
+
+// True iff CONFIG_NET_CLS_BPF is enabled in /proc/config.gz
+bool kernelSupportsNetClsBpf(void) {
+    return doKernelSupportsNetClsBpf() == W_EXITCODE(0, 0);
+}
+
+// See Linux kernel source in include/net/flow.h
+#define LOOPBACK_IFINDEX 1
+
+TEST_F(OffloadUtilsTest, AttachReplaceDetachClsactLo) {
+    // Technically does not depend on ebpf, but does depend on clsact,
+    // and we do not really care if it works on pre-4.9-Q anyway.
+    SKIP_IF_BPF_NOT_SUPPORTED;
+    if (!kernelSupportsNetSchIngress()) return;
+
+    int fd = openNetlinkSocket();
+    ASSERT_LE(3, fd);
+
+    // This attaches and detaches a configuration-less and thus no-op clsact
+    // qdisc to loopback interface (and it takes fractions of a second)
+    EXPECT_EQ(0, tcQdiscAddDevClsact(fd, LOOPBACK_IFINDEX));
+    EXPECT_EQ(0, tcQdiscReplaceDevClsact(fd, LOOPBACK_IFINDEX));
+    EXPECT_EQ(0, tcQdiscDelDevClsact(fd, LOOPBACK_IFINDEX));
+    close(fd);
+}
+
+static void checkAttachBpfFilterClsactLo(const bool ingress, const bool ethernet) {
+    // This test requires kernel 4.9-Q or better
+    SKIP_IF_BPF_NOT_SUPPORTED;
+    if (!kernelSupportsNetSchIngress()) return;
+    if (!kernelSupportsNetClsBpf()) return;
+
+    int bpf_fd = ingress ? getClatIngressProgFd(ethernet) : getClatEgressProgFd(ethernet);
+    ASSERT_LE(3, bpf_fd);
+
+    int fd = openNetlinkSocket();
+    EXPECT_LE(3, fd);
+    if (fd >= 0) {
+        // This attaches and detaches a clsact plus ebpf program to loopback
+        // interface, but it should not affect traffic by virtue of us not
+        // actually populating the ebpf control map.
+        // Furthermore: it only takes fractions of a second.
+        EXPECT_EQ(0, tcQdiscAddDevClsact(fd, LOOPBACK_IFINDEX));
+        if (ingress) {
+            EXPECT_EQ(0, tcFilterAddDevIngressBpf(fd, LOOPBACK_IFINDEX, bpf_fd, ethernet));
+        } else {
+            EXPECT_EQ(0, tcFilterAddDevEgressBpf(fd, LOOPBACK_IFINDEX, bpf_fd, ethernet));
+        }
+        EXPECT_EQ(0, tcQdiscDelDevClsact(fd, LOOPBACK_IFINDEX));
+        close(fd);
+    }
+
+    close(bpf_fd);
+}
+
+TEST_F(OffloadUtilsTest, CheckAttachBpfFilterRawIpClsactEgressLo) {
+    checkAttachBpfFilterClsactLo(/*ingress*/ false, /*ethernet*/ false);
+}
+
+TEST_F(OffloadUtilsTest, CheckAttachBpfFilterEthernetClsactEgressLo) {
+    checkAttachBpfFilterClsactLo(/*ingress*/ false, /*ethernet*/ true);
+}
+
+TEST_F(OffloadUtilsTest, CheckAttachBpfFilterRawIpClsactIngressLo) {
+    checkAttachBpfFilterClsactLo(/*ingress*/ true, /*ethernet*/ false);
+}
+
+TEST_F(OffloadUtilsTest, CheckAttachBpfFilterEthernetClsactIngressLo) {
+    checkAttachBpfFilterClsactLo(/*ingress*/ true, /*ethernet*/ true);
+}
+
+}  // namespace net
+}  // namespace android