Bpf Util Lib in Common Location
Add bpf lib to load and attach BPF programs in commonly accesible
location.
Bug: 179733303
Change-Id: I17b68abb14e816e7210bc603ffda44e10fb73d2f
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index a311eb5..d8c91e3 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -112,6 +112,7 @@
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 0000000..94af11b
--- /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 0000000..39a2795
--- /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 0000000..0f2ebbd
--- /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 <android-base/unique_fd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/scoped_utf_chars.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#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