diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp index 15cf47a1b6..500c69664d 100644 --- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp @@ -34,7 +34,6 @@ #include #include -#include "libclat/bpfhelper.h" #include "libclat/clatutils.h" #include "nativehelper/scoped_utf_chars.h" @@ -257,46 +256,6 @@ static void com_android_server_connectivity_ClatCoordinator_configurePacketSocke } } -int initTracker(const std::string& iface, const std::string& pfx96, const std::string& v4, - const std::string& v6, net::clat::ClatdTracker* output) { - strlcpy(output->iface, iface.c_str(), sizeof(output->iface)); - output->ifIndex = if_nametoindex(iface.c_str()); - if (output->ifIndex == 0) { - ALOGE("interface %s not found", output->iface); - return -1; - } - - unsigned len = snprintf(output->v4iface, sizeof(output->v4iface), - "%s%s", DEVICEPREFIX, iface.c_str()); - if (len >= sizeof(output->v4iface)) { - ALOGE("interface name too long '%s'", output->v4iface); - return -1; - } - - output->v4ifIndex = if_nametoindex(output->v4iface); - if (output->v4ifIndex == 0) { - ALOGE("v4-interface %s not found", output->v4iface); - return -1; - } - - if (!inet_pton(AF_INET6, pfx96.c_str(), &output->pfx96)) { - ALOGE("invalid IPv6 address specified for plat prefix: %s", pfx96.c_str()); - return -1; - } - - if (!inet_pton(AF_INET, v4.c_str(), &output->v4)) { - ALOGE("Invalid IPv4 address %s", v4.c_str()); - return -1; - } - - if (!inet_pton(AF_INET6, v6.c_str(), &output->v6)) { - ALOGE("Invalid source address %s", v6.c_str()); - return -1; - } - - return 0; -} - static jint com_android_server_connectivity_ClatCoordinator_startClatd( JNIEnv* env, jobject clazz, jobject tunJavaFd, jobject readSockJavaFd, jobject writeSockJavaFd, jstring iface, jstring pfx96, jstring v4, jstring v6) { diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp index 17ee9967f3..68e4dc4f30 100644 --- a/service/native/libs/libclat/Android.bp +++ b/service/native/libs/libclat/Android.bp @@ -19,19 +19,12 @@ package { cc_library_static { name: "libclat", defaults: ["netd_defaults"], - header_libs: [ - "bpf_connectivity_headers", - "libbase_headers", - ], srcs: [ - "TcUtils.cpp", // TODO: move to frameworks/libs/net - "bpfhelper.cpp", "clatutils.cpp", ], stl: "libc++_static", static_libs: [ "libip_checksum", - "libnetdutils", // for netdutils/UidConstants.h in bpf_shared.h ], shared_libs: ["liblog"], export_include_dirs: ["include"], @@ -43,11 +36,7 @@ cc_test { name: "libclat_test", defaults: ["netd_defaults"], test_suites: ["device-tests"], - header_libs: [ - "bpf_connectivity_headers", - ], srcs: [ - "TcUtilsTest.cpp", "clatutils_test.cpp", ], static_libs: [ @@ -55,8 +44,6 @@ cc_test { "libclat", "libip_checksum", "libnetd_test_tun_interface", - "libnetdutils", // for netdutils/UidConstants.h in bpf_shared.h - "libtcutils", ], shared_libs: [ "liblog", diff --git a/service/native/libs/libclat/TcUtils.cpp b/service/native/libs/libclat/TcUtils.cpp deleted file mode 100644 index cdfb763e63..0000000000 --- a/service/native/libs/libclat/TcUtils.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#define LOG_TAG "TcUtils" - -#include "libclat/TcUtils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "android-base/unique_fd.h" - -namespace android { -namespace net { - -using std::max; - -// Sync from system/netd/server/NetlinkCommands.h -const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0}; -const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK; - -static int doSIOCGIF(const std::string& interface, int opt) { - base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)); - - if (ufd < 0) { - const int err = errno; - ALOGE("socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)"); - return -err; - }; - - struct ifreq ifr = {}; - // We use strncpy() instead of strlcpy() since kernel has to be able - // to handle non-zero terminated junk passed in by userspace anyway, - // and this way too long interface names (more than IFNAMSIZ-1 = 15 - // characters plus terminating NULL) will not get truncated to 15 - // characters and zero-terminated and thus potentially erroneously - // match a truncated interface if one were to exist. - strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name)); - - if (ioctl(ufd, opt, &ifr, sizeof(ifr))) return -errno; - - if (opt == SIOCGIFHWADDR) return ifr.ifr_hwaddr.sa_family; - if (opt == SIOCGIFMTU) return ifr.ifr_mtu; - return -EINVAL; -} - -int hardwareAddressType(const std::string& interface) { - return doSIOCGIF(interface, SIOCGIFHWADDR); -} - -int deviceMTU(const std::string& interface) { - return doSIOCGIF(interface, SIOCGIFMTU); -} - -base::Result 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_NONE: - 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) { - base::unique_fd fd(socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)); - if (fd == -1) { - const int err = errno; - ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)"); - return -err; - } - - static constexpr int on = 1; - int rv = setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on)); - if (rv) ALOGE("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, %d)", on); - - // this is needed to get sane strace netlink parsing, it allocates the pid - rv = bind(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR)); - if (rv) { - const int err = errno; - ALOGE("bind(fd, {AF_NETLINK, 0, 0})"); - return -err; - } - - // we do not want to receive messages from anyone besides the kernel - rv = connect(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR)); - if (rv) { - const int err = errno; - ALOGE("connect(fd, {AF_NETLINK, 0, 0})"); - return -err; - } - - rv = send(fd, req, len, 0); - if (rv == -1) return -errno; - if (rv != len) return -EMSGSIZE; - - struct { - nlmsghdr h; - nlmsgerr e; - char buf[256]; - } resp = {}; - - rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC); - - if (rv == -1) { - const int err = errno; - ALOGE("recv() failed"); - return -err; - } - - if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) { - ALOGE("recv() returned short packet: %d", rv); - return -EMSGSIZE; - } - - if (resp.h.nlmsg_len != (unsigned)rv) { - ALOGE("recv() returned invalid header length: %d != %d", resp.h.nlmsg_len, rv); - return -EBADMSG; - } - - if (resp.h.nlmsg_type != NLMSG_ERROR) { - ALOGE("recv() did not return NLMSG_ERROR message: %d", resp.h.nlmsg_type); - return -EBADMSG; - } - - return resp.e.error; // returns 0 on success -} - -// ADD: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_EXCL|NLM_F_CREATE -// REPLACE: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_CREATE|NLM_F_REPLACE -// DEL: nlMsgType=RTM_DELQDISC nlMsgFlags=0 -int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags) { - // This is the name of the qdisc we are attaching. - // Some hoop jumping to make this compile time constant with known size, - // so that the structure declaration is well defined at compile time. -#define CLSACT "clsact" - // sizeof() includes the terminating NULL - static constexpr size_t ASCIIZ_LEN_CLSACT = sizeof(CLSACT); - - const struct { - nlmsghdr n; - tcmsg t; - struct { - nlattr attr; - char str[NLMSG_ALIGN(ASCIIZ_LEN_CLSACT)]; - } kind; - } req = { - .n = - { - .nlmsg_len = sizeof(req), - .nlmsg_type = nlMsgType, - .nlmsg_flags = static_cast<__u16>(NETLINK_REQUEST_FLAGS | nlMsgFlags), - }, - .t = - { - .tcm_family = AF_UNSPEC, - .tcm_ifindex = ifIndex, - .tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0), - .tcm_parent = TC_H_CLSACT, - }, - .kind = - { - .attr = - { - .nla_len = NLA_HDRLEN + ASCIIZ_LEN_CLSACT, - .nla_type = TCA_KIND, - }, - .str = CLSACT, - }, - }; -#undef CLSACT - - return sendAndProcessNetlinkResponse(&req, sizeof(req)); -} - -// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/... -// direct-action -int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet) { - // This is the name of the filter we're attaching (ie. this is the 'bpf' - // packet classifier enabled by kernel config option CONFIG_NET_CLS_BPF. - // - // We go through some hoops in order to make this compile time constants - // so that we can define the struct further down the function with the - // field for this sized correctly already during the build. -#define BPF "bpf" - // sizeof() includes the terminating NULL - static constexpr size_t ASCIIZ_LEN_BPF = sizeof(BPF); - - // This is to replicate program name suffix used by 'tc' Linux cli - // when it attaches programs. -#define FSOBJ_SUFFIX ":[*fsobj]" - - // This macro expands (from header files) to: - // prog_clatd_schedcls_ingress6_clat_rawip:[*fsobj] - // and is the name of the pinned ingress ebpf program for ARPHRD_RAWIP interfaces. - // (also compatible with anything that has 0 size L2 header) - static constexpr char name_clat_rx_rawip[] = CLAT_INGRESS6_PROG_RAWIP_NAME FSOBJ_SUFFIX; - - // This macro expands (from header files) to: - // prog_clatd_schedcls_ingress6_clat_ether:[*fsobj] - // and is the name of the pinned ingress ebpf program for ARPHRD_ETHER interfaces. - // (also compatible with anything that has standard ethernet header) - static constexpr char name_clat_rx_ether[] = CLAT_INGRESS6_PROG_ETHER_NAME FSOBJ_SUFFIX; - - // This macro expands (from header files) to: - // prog_clatd_schedcls_egress4_clat_rawip:[*fsobj] - // and is the name of the pinned egress ebpf program for ARPHRD_RAWIP interfaces. - // (also compatible with anything that has 0 size L2 header) - static constexpr char name_clat_tx_rawip[] = CLAT_EGRESS4_PROG_RAWIP_NAME FSOBJ_SUFFIX; - - // This macro expands (from header files) to: - // prog_clatd_schedcls_egress4_clat_ether:[*fsobj] - // and is the name of the pinned egress ebpf program for ARPHRD_ETHER interfaces. - // (also compatible with anything that has standard ethernet header) - static constexpr char name_clat_tx_ether[] = CLAT_EGRESS4_PROG_ETHER_NAME FSOBJ_SUFFIX; - -#undef FSOBJ_SUFFIX - - // The actual name we'll use is determined at run time via 'ethernet' and 'ingress' - // booleans. We need to compile time allocate enough space in the struct - // hence this macro magic to make sure we have enough space for either - // possibility. In practice some of these are actually the same size. - static constexpr size_t ASCIIZ_MAXLEN_NAME = max({ - sizeof(name_clat_rx_rawip), - sizeof(name_clat_rx_ether), - sizeof(name_clat_tx_rawip), - sizeof(name_clat_tx_ether), - }); - - // These are not compile time constants: 'name' is used in strncpy below - const char* const name_clat_rx = ethernet ? name_clat_rx_ether : name_clat_rx_rawip; - const char* const name_clat_tx = ethernet ? name_clat_tx_ether : name_clat_tx_rawip; - const char* const name = ingress ? name_clat_rx : name_clat_tx; - - struct { - nlmsghdr n; - tcmsg t; - struct { - nlattr attr; - char str[NLMSG_ALIGN(ASCIIZ_LEN_BPF)]; - } kind; - struct { - nlattr attr; - struct { - nlattr attr; - __u32 u32; - } fd; - struct { - nlattr attr; - char str[NLMSG_ALIGN(ASCIIZ_MAXLEN_NAME)]; - } name; - struct { - nlattr attr; - __u32 u32; - } flags; - } options; - } req = { - .n = - { - .nlmsg_len = sizeof(req), - .nlmsg_type = RTM_NEWTFILTER, - .nlmsg_flags = NETLINK_REQUEST_FLAGS | NLM_F_EXCL | NLM_F_CREATE, - }, - .t = - { - .tcm_family = AF_UNSPEC, - .tcm_ifindex = ifIndex, - .tcm_handle = TC_H_UNSPEC, - .tcm_parent = TC_H_MAKE(TC_H_CLSACT, - ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS), - .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)), - }, - .kind = - { - .attr = - { - .nla_len = sizeof(req.kind), - .nla_type = TCA_KIND, - }, - .str = BPF, - }, - .options = - { - .attr = - { - .nla_len = sizeof(req.options), - .nla_type = NLA_F_NESTED | TCA_OPTIONS, - }, - .fd = - { - .attr = - { - .nla_len = sizeof(req.options.fd), - .nla_type = TCA_BPF_FD, - }, - .u32 = static_cast<__u32>(bpfFd), - }, - .name = - { - .attr = - { - .nla_len = sizeof(req.options.name), - .nla_type = TCA_BPF_NAME, - }, - // Visible via 'tc filter show', but - // is overwritten by strncpy below - .str = "placeholder", - }, - .flags = - { - .attr = - { - .nla_len = sizeof(req.options.flags), - .nla_type = TCA_BPF_FLAGS, - }, - .u32 = TCA_BPF_FLAG_ACT_DIRECT, - }, - }, - }; -#undef BPF - - strncpy(req.options.name.str, name, sizeof(req.options.name.str)); - - return sendAndProcessNetlinkResponse(&req, sizeof(req)); -} - -// tc filter del dev .. in/egress prio 4 protocol .. -int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) { - const struct { - nlmsghdr n; - tcmsg t; - } req = { - .n = - { - .nlmsg_len = sizeof(req), - .nlmsg_type = RTM_DELTFILTER, - .nlmsg_flags = NETLINK_REQUEST_FLAGS, - }, - .t = - { - .tcm_family = AF_UNSPEC, - .tcm_ifindex = ifIndex, - .tcm_handle = TC_H_UNSPEC, - .tcm_parent = TC_H_MAKE(TC_H_CLSACT, - ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS), - .tcm_info = (static_cast(prio) << 16) | - static_cast(htons(proto)), - }, - }; - - return sendAndProcessNetlinkResponse(&req, sizeof(req)); -} - -} // namespace net -} // namespace android diff --git a/service/native/libs/libclat/TcUtilsTest.cpp b/service/native/libs/libclat/TcUtilsTest.cpp deleted file mode 100644 index 08f3042741..0000000000 --- a/service/native/libs/libclat/TcUtilsTest.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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. - * - * TcUtilsTest.cpp - unit tests for TcUtils.cpp - */ - -#include - -#include "libclat/TcUtils.h" - -#include -#include -#include - -#include "bpf/BpfUtils.h" -#include "bpf_shared.h" - -namespace android { -namespace net { - -class TcUtilsTest : public ::testing::Test { - public: - void SetUp() {} -}; - -TEST_F(TcUtilsTest, HardwareAddressTypeOfNonExistingIf) { - ASSERT_EQ(-ENODEV, hardwareAddressType("not_existing_if")); -} - -TEST_F(TcUtilsTest, HardwareAddressTypeOfLoopback) { - ASSERT_EQ(ARPHRD_LOOPBACK, hardwareAddressType("lo")); -} - -// If wireless 'wlan0' interface exists it should be Ethernet. -TEST_F(TcUtilsTest, 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(TcUtilsTest, 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(TcUtilsTest, IsEthernetOfNonExistingIf) { - auto res = isEthernet("not_existing_if"); - ASSERT_FALSE(res.ok()); - ASSERT_EQ(ENODEV, res.error().code()); -} - -TEST_F(TcUtilsTest, 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(TcUtilsTest, 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(TcUtilsTest, IsEthernetOfCellular) { - auto res = isEthernet("rmnet_data0"); - if (!res.ok() && res.error().code() == ENODEV) return; - - ASSERT_RESULT_OK(res); - ASSERT_FALSE(res.value()); -} - -TEST_F(TcUtilsTest, DeviceMTUOfNonExistingIf) { - ASSERT_EQ(-ENODEV, deviceMTU("not_existing_if")); -} - -TEST_F(TcUtilsTest, DeviceMTUofLoopback) { - ASSERT_EQ(65536, deviceMTU("lo")); -} - -TEST_F(TcUtilsTest, GetClatEgress4MapFd) { - int fd = getClatEgress4MapFd(); - ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3 - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -TEST_F(TcUtilsTest, GetClatEgress4RawIpProgFd) { - int fd = getClatEgress4ProgFd(RAWIP); - ASSERT_GE(fd, 3); - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -TEST_F(TcUtilsTest, GetClatEgress4EtherProgFd) { - int fd = getClatEgress4ProgFd(ETHER); - ASSERT_GE(fd, 3); - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -TEST_F(TcUtilsTest, GetClatIngress6MapFd) { - int fd = getClatIngress6MapFd(); - ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3 - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -TEST_F(TcUtilsTest, GetClatIngress6RawIpProgFd) { - int fd = getClatIngress6ProgFd(RAWIP); - ASSERT_GE(fd, 3); - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -TEST_F(TcUtilsTest, GetClatIngress6EtherProgFd) { - int fd = getClatIngress6ProgFd(ETHER); - ASSERT_GE(fd, 3); - EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD)); - close(fd); -} - -// See Linux kernel source in include/net/flow.h -#define LOOPBACK_IFINDEX 1 - -TEST_F(TcUtilsTest, AttachReplaceDetachClsactLo) { - // 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(LOOPBACK_IFINDEX)); - EXPECT_EQ(0, tcQdiscReplaceDevClsact(LOOPBACK_IFINDEX)); - EXPECT_EQ(0, tcQdiscDelDevClsact(LOOPBACK_IFINDEX)); - EXPECT_EQ(-EINVAL, tcQdiscDelDevClsact(LOOPBACK_IFINDEX)); -} - -static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool ethernet) { - // Older kernels return EINVAL instead of ENOENT due to lacking proper error propagation... - const int errNOENT = android::bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; - - int clatBpfFd = ingress ? getClatIngress6ProgFd(ethernet) : getClatEgress4ProgFd(ethernet); - ASSERT_GE(clatBpfFd, 3); - - // 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(-EINVAL, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX)); - EXPECT_EQ(-EINVAL, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX)); - EXPECT_EQ(0, tcQdiscAddDevClsact(LOOPBACK_IFINDEX)); - EXPECT_EQ(-errNOENT, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX)); - EXPECT_EQ(-errNOENT, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX)); - if (ingress) { - EXPECT_EQ(0, tcFilterAddDevIngressClatIpv6(LOOPBACK_IFINDEX, clatBpfFd, ethernet)); - EXPECT_EQ(0, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX)); - } else { - EXPECT_EQ(0, tcFilterAddDevEgressClatIpv4(LOOPBACK_IFINDEX, clatBpfFd, ethernet)); - EXPECT_EQ(0, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX)); - } - EXPECT_EQ(-errNOENT, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX)); - EXPECT_EQ(-errNOENT, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX)); - EXPECT_EQ(0, tcQdiscDelDevClsact(LOOPBACK_IFINDEX)); - EXPECT_EQ(-EINVAL, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX)); - EXPECT_EQ(-EINVAL, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX)); - - close(clatBpfFd); -} - -TEST_F(TcUtilsTest, CheckAttachBpfFilterRawIpClsactEgressLo) { - checkAttachDetachBpfFilterClsactLo(EGRESS, RAWIP); -} - -TEST_F(TcUtilsTest, CheckAttachBpfFilterEthernetClsactEgressLo) { - checkAttachDetachBpfFilterClsactLo(EGRESS, ETHER); -} - -TEST_F(TcUtilsTest, CheckAttachBpfFilterRawIpClsactIngressLo) { - checkAttachDetachBpfFilterClsactLo(INGRESS, RAWIP); -} - -TEST_F(TcUtilsTest, CheckAttachBpfFilterEthernetClsactIngressLo) { - checkAttachDetachBpfFilterClsactLo(INGRESS, ETHER); -} - -} // namespace net -} // namespace android diff --git a/service/native/libs/libclat/bpfhelper.cpp b/service/native/libs/libclat/bpfhelper.cpp deleted file mode 100644 index 475675fa56..0000000000 --- a/service/native/libs/libclat/bpfhelper.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2021 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. - * - * main.c - main function - */ -#define LOG_TAG "bpfhelper" - -#include "libclat/bpfhelper.h" - -#include -#include - -#include "bpf/BpfMap.h" -#include "libclat/TcUtils.h" - -#define DEVICEPREFIX "v4-" - -using android::base::unique_fd; -using android::bpf::BpfMap; - -BpfMap mClatEgress4Map; -BpfMap mClatIngress6Map; - -namespace android { -namespace net { -namespace clat { - -// TODO: have a clearMap function to remove all stubs while system server crash. -// For long term, move bpf access into java and map initialization should live -// ClatCoordinator constructor. -int initMaps(void) { - int rv = getClatEgress4MapFd(); - if (rv < 0) { - ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv)); - return -rv; - } - mClatEgress4Map.reset(rv); - - rv = getClatIngress6MapFd(); - if (rv < 0) { - ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv)); - mClatEgress4Map.reset(-1); - return -rv; - } - mClatIngress6Map.reset(rv); - - return 0; -} - -void maybeStartBpf(const ClatdTracker& tracker) { - 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; - } - - // This program will be attached to the v4-* interface which is a TUN and thus always rawip. - int rv = getClatEgress4ProgFd(RAWIP); - if (rv < 0) { - ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv)); - return; - } - unique_fd txRawIpProgFd(rv); - - rv = getClatIngress6ProgFd(isEthernet.value()); - if (rv < 0) { - ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv)); - return; - } - unique_fd rxProgFd(rv); - - // We do tc setup *after* populating the maps, so scanning through them - // can always be used to tell us what needs cleanup. - - // Usually the clsact will be added in RouteController::addInterfaceToPhysicalNetwork. - // But clat is started before the v4- interface is added to the network. The clat startup have - // to add clsact of v4- tun interface first for adding bpf filter in maybeStartBpf. - // TODO: move "qdisc add clsact" of v4- tun interface out from ClatdController. - rv = tcQdiscAddDevClsact(tracker.v4ifIndex); - if (rv) { - ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface, - strerror(-rv)); - return; - } - - rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP); - if (rv) { - ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex, - tracker.v4iface, strerror(-rv)); - - // The v4- interface clsact is not deleted for unwinding error because once it is created - // with interface addition, the lifetime is till interface deletion. Moreover, the clsact - // has no clat filter now. It should not break anything. - - return; - } - - rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value()); - if (rv) { - ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex, - tracker.iface, isEthernet.value(), strerror(-rv)); - rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex); - if (rv) { - ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex, - tracker.v4iface, strerror(-rv)); - } - - // The v4- interface clsact is not deleted. See the reason in the error unwinding code of - // the egress filter attaching of v4- tun interface. - - return; - } - - // success -} - -void maybeStopBpf(const ClatdTracker& tracker) { - int rv = tcFilterDelDevIngressClatIpv6(tracker.ifIndex); - if (rv < 0) { - ALOGE("tcFilterDelDevIngressClatIpv6(%d[%s]) failure: %s", tracker.ifIndex, tracker.iface, - strerror(-rv)); - } - - rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex); - if (rv < 0) { - ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex, - tracker.v4iface, strerror(-rv)); - } -} - -} // namespace clat -} // namespace net -} // namespace android diff --git a/service/native/libs/libclat/include/libclat/TcUtils.h b/service/native/libs/libclat/include/libclat/TcUtils.h deleted file mode 100644 index 212838ed32..0000000000 --- a/service/native/libs/libclat/include/libclat/TcUtils.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include "bpf/BpfUtils.h" -#include "bpf_shared.h" - -namespace android { -namespace net { - -// For better code clarity - do not change values - used for booleans like -// with_ethernet_header or isEthernet. -constexpr bool RAWIP = false; -constexpr bool ETHER = true; - -// For better code clarity when used for 'bool ingress' parameter. -constexpr bool EGRESS = false; -constexpr bool INGRESS = true; - -// The priority of clat hook - must be after tethering. -constexpr uint16_t PRIO_CLAT = 4; - -// this returns an ARPHRD_* constant or a -errno -int hardwareAddressType(const std::string& interface); - -// return MTU or -errno -int deviceMTU(const std::string& interface); - -base::Result isEthernet(const std::string& interface); - -inline int getClatEgress4MapFd(void) { - const int fd = bpf::mapRetrieveRW(CLAT_EGRESS4_MAP_PATH); - return (fd == -1) ? -errno : fd; -} - -inline int getClatEgress4ProgFd(bool with_ethernet_header) { - const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_EGRESS4_PROG_ETHER_PATH - : CLAT_EGRESS4_PROG_RAWIP_PATH); - return (fd == -1) ? -errno : fd; -} - -inline int getClatIngress6MapFd(void) { - const int fd = bpf::mapRetrieveRW(CLAT_INGRESS6_MAP_PATH); - return (fd == -1) ? -errno : fd; -} - -inline int getClatIngress6ProgFd(bool with_ethernet_header) { - const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_INGRESS6_PROG_ETHER_PATH - : CLAT_INGRESS6_PROG_RAWIP_PATH); - return (fd == -1) ? -errno : fd; -} - -int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags); - -inline int tcQdiscAddDevClsact(int ifIndex) { - return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE); -} - -inline int tcQdiscReplaceDevClsact(int ifIndex) { - return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE); -} - -inline int tcQdiscDelDevClsact(int ifIndex) { - return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0); -} - -// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/... -// direct-action -int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet); - -// tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action -inline int tcFilterAddDevIngressClatIpv6(int ifIndex, int bpfFd, bool ethernet) { - return tcFilterAddDevBpf(ifIndex, INGRESS, ETH_P_IPV6, bpfFd, ethernet); -} - -// tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action -inline int tcFilterAddDevEgressClatIpv4(int ifIndex, int bpfFd, bool ethernet) { - return tcFilterAddDevBpf(ifIndex, EGRESS, ETH_P_IP, bpfFd, ethernet); -} - -// tc filter del dev .. in/egress prio .. protocol .. -int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto); - -// tc filter del dev .. ingress prio 4 protocol ipv6 -inline int tcFilterDelDevIngressClatIpv6(int ifIndex) { - return tcFilterDelDev(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6); -} - -// tc filter del dev .. egress prio 4 protocol ip -inline int tcFilterDelDevEgressClatIpv4(int ifIndex) { - return tcFilterDelDev(ifIndex, EGRESS, PRIO_CLAT, ETH_P_IP); -} - -} // namespace net -} // namespace android diff --git a/service/native/libs/libclat/include/libclat/bpfhelper.h b/service/native/libs/libclat/include/libclat/bpfhelper.h deleted file mode 100644 index c0328c0715..0000000000 --- a/service/native/libs/libclat/include/libclat/bpfhelper.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2021 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. - -#pragma once - -#include -#include - -namespace android { -namespace net { -namespace clat { - -struct ClatdTracker { - unsigned ifIndex; - char iface[IFNAMSIZ]; - unsigned v4ifIndex; - char v4iface[IFNAMSIZ]; - in_addr v4; - in6_addr v6; - in6_addr pfx96; -}; - -int initMaps(void); -void maybeStartBpf(const ClatdTracker& tracker); -void maybeStopBpf(const ClatdTracker& tracker); - -} // namespace clat -} // namespace net -} // namespace android