diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a311eb577f..d8c91e3387 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -112,6 +112,7 @@ java_library { srcs: [ "device/com/android/net/module/util/BpfBitmap.java", "device/com/android/net/module/util/BpfMap.java", + "device/com/android/net/module/util/BpfUtils.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/IBpfMap.java", "device/com/android/net/module/util/JniUtil.java", diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java new file mode 100644 index 0000000000..94af11b347 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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. + */ +package com.android.net.module.util; + +import androidx.annotation.NonNull; + +import java.io.IOException; + +/** + * The classes and the methods for BPF utilization. + * + * {@hide} + */ +public class BpfUtils { + static { + System.loadLibrary(JniUtil.getJniLibraryName(BpfUtils.class.getPackage())); + } + + // Defined in include/uapi/linux/bpf.h. Only adding the CGROUPS currently being used for now. + public static final int BPF_CGROUP_INET_INGRESS = 0; + public static final int BPF_CGROUP_INET_EGRESS = 1; + public static final int BPF_CGROUP_INET4_BIND = 8; + public static final int BPF_CGROUP_INET6_BIND = 9; + + + /** + * Attach BPF program to CGROUP + */ + public static void attachProgram(int type, @NonNull String programPath, + @NonNull String cgroupPath, int flags) throws IOException { + native_attachProgramToCgroup(type, programPath, cgroupPath, flags); + } + + /** + * Detach BPF program from CGROUP + */ + public static void detachProgram(int type, @NonNull String cgroupPath) + throws IOException { + native_detachProgramFromCgroup(type, cgroupPath); + } + + /** + * Detach single BPF program from CGROUP + */ + public static void detachSingleProgram(int type, @NonNull String programPath, + @NonNull String cgroupPath) throws IOException { + native_detachSingleProgramFromCgroup(type, programPath, cgroupPath); + } + + private static native boolean native_attachProgramToCgroup(int type, String programPath, + String cgroupPath, int flags) throws IOException; + private static native boolean native_detachProgramFromCgroup(int type, String cgroupPath) + throws IOException; + private static native boolean native_detachSingleProgramFromCgroup(int type, + String programPath, String cgroupPath) throws IOException; +} diff --git a/staticlibs/native/bpfutiljni/Android.bp b/staticlibs/native/bpfutiljni/Android.bp new file mode 100644 index 0000000000..39a2795086 --- /dev/null +++ b/staticlibs/native/bpfutiljni/Android.bp @@ -0,0 +1,44 @@ +// Copyright (C) 2022 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libnet_utils_device_common_bpfutils", + srcs: ["com_android_net_module_util_BpfUtils.cpp"], + header_libs: [ + "bpf_syscall_wrappers", + "jni_headers", + ], + shared_libs: [ + "libbase", + "liblog", + "libnativehelper_compat_libc++", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + visibility: [ + "//packages/modules/Connectivity/service", + ], +} diff --git a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp new file mode 100644 index 0000000000..0f2ebbd49a --- /dev/null +++ b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BpfSyscallWrappers.h" + +namespace android { + +using base::unique_fd; + +// If attach fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_attachProgramToCgroup(JNIEnv *env, + jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + ScopedUtfChars bpfProg(env, bpfProgPath); + unique_fd bpf_fd(bpf::retrieveProgram(bpfProg.c_str())); + if (bpf_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to retrieve bpf program from %s: %s", + bpfProg.c_str(), strerror(errno)); + return false; + } + if (bpf::attachProgram((bpf_attach_type) type, bpf_fd, cg_fd, flags)) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to attach bpf program %s to %s: %s", + bpfProg.c_str(), dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +// If detach fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_detachProgramFromCgroup(JNIEnv *env, + jobject clazz, jint type, jstring cgroupPath) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + if (bpf::detachProgram((bpf_attach_type) type, cg_fd)) { + jniThrowExceptionFmt(env, "Failed to detach bpf program from %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +// If detach single program fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup(JNIEnv *env, + jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + ScopedUtfChars bpfProg(env, bpfProgPath); + unique_fd bpf_fd(bpf::retrieveProgram(bpfProg.c_str())); + if (bpf_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to retrieve bpf program from %s: %s", + bpfProg.c_str(), strerror(errno)); + return false; + } + if (bpf::detachSingleProgram((bpf_attach_type) type, bpf_fd, cg_fd)) { + jniThrowExceptionFmt(env, "Failed to detach bpf program %s from %s: %s", + bpfProg.c_str(), dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "native_attachProgramToCgroup", "(ILjava/lang/String;Ljava/lang/String;I)Z", + (void*) com_android_net_module_util_BpfUtil_attachProgramToCgroup }, + { "native_detachProgramFromCgroup", "(ILjava/lang/String;)Z", + (void*) com_android_net_module_util_BpfUtil_detachProgramFromCgroup }, + { "native_detachSingleProgramFromCgroup", "(ILjava/lang/String;Ljava/lang/String;)Z", + (void*) com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup }, +}; + +int register_com_android_net_module_util_BpfUtils(JNIEnv* env, char const* class_name) { + return jniRegisterNativeMethods(env, + class_name, + gMethods, NELEM(gMethods)); +} + +}; // namespace android