Dump counters in "dumpsys tethering bpf". am: 4e92da06fa am: e033a1e543

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1575051

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ib449565583901259f0c21764d566637eace5f5f8
This commit is contained in:
Lorenzo Colitti
2021-02-10 05:31:03 +00:00
committed by Automerger Merge Worker
4 changed files with 101 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
/*
* 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.
*/
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include "bpf_tethering.h"
namespace android {
static jobjectArray getBpfCounterNames(JNIEnv *env) {
size_t size = BPF_TETHER_ERR__MAX;
jobjectArray ret = env->NewObjectArray(size, env->FindClass("java/lang/String"), nullptr);
for (int i = 0; i < size; i++) {
env->SetObjectArrayElement(ret, i, env->NewStringUTF(bpf_tether_errors[i]));
}
return ret;
}
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "getBpfCounterNames", "()[Ljava/lang/String;", (void*) getBpfCounterNames },
};
int register_com_android_networkstack_tethering_BpfCoordinator(JNIEnv* env) {
return jniRegisterNativeMethods(env,
"com/android/networkstack/tethering/BpfCoordinator",
gMethods, NELEM(gMethods));
}
}; // namespace android

View File

@@ -24,6 +24,7 @@ namespace android {
int register_android_net_util_TetheringUtils(JNIEnv* env);
int register_com_android_networkstack_tethering_BpfMap(JNIEnv* env);
int register_com_android_networkstack_tethering_BpfCoordinator(JNIEnv* env);
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv *env;
@@ -36,6 +37,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
if (register_com_android_networkstack_tethering_BpfMap(env) < 0) return JNI_ERR;
if (register_com_android_networkstack_tethering_BpfCoordinator(env) < 0) return JNI_ERR;
return JNI_VERSION_1_6;
}

View File

@@ -59,6 +59,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.Struct;
import com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim;
import java.net.Inet4Address;
@@ -84,6 +85,13 @@ import java.util.Set;
* @hide
*/
public class BpfCoordinator {
// Ensure the JNI code is loaded. In production this will already have been loaded by
// TetherService, but for tests it needs to be either loaded here or loaded by every test.
// TODO: is there a better way?
static {
System.loadLibrary("tetherutilsjni");
}
static final boolean DOWNSTREAM = true;
static final boolean UPSTREAM = false;
@@ -97,6 +105,10 @@ public class BpfCoordinator {
private static final String TETHER_UPSTREAM6_FS_PATH = makeMapPath(UPSTREAM, 6);
private static final String TETHER_STATS_MAP_PATH = makeMapPath("stats");
private static final String TETHER_LIMIT_MAP_PATH = makeMapPath("limit");
private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
/** The names of all the BPF counters defined in bpf_tethering.h. */
public static final String[] sBpfCounterNames = getBpfCounterNames();
private static String makeMapPath(String which) {
return "/sys/fs/bpf/tethering/map_offload_tether_" + which + "_map";
@@ -717,6 +729,12 @@ public class BpfCoordinator {
dumpIpv4ForwardingRules(pw);
pw.decreaseIndent();
pw.println();
pw.println("Forwarding counters:");
pw.increaseIndent();
dumpCounters(pw);
pw.decreaseIndent();
dumpDone.open();
});
if (!dumpDone.block(DUMP_TIMEOUT_MS)) {
@@ -814,6 +832,36 @@ public class BpfCoordinator {
pw.decreaseIndent();
}
/**
* Simple struct that only contains a u32. Must be public because Struct needs access to it.
* TODO: make this a public inner class of Struct so anyone can use it as, e.g., Struct.U32?
*/
public static class U32Struct extends Struct {
@Struct.Field(order = 0, type = Struct.Type.U32)
public long val;
}
private void dumpCounters(@NonNull IndentingPrintWriter pw) {
try (BpfMap<U32Struct, U32Struct> map = new BpfMap<>(TETHER_ERROR_MAP_PATH,
BpfMap.BPF_F_RDONLY, U32Struct.class, U32Struct.class)) {
map.forEach((k, v) -> {
String counterName;
try {
counterName = sBpfCounterNames[(int) k.val];
} catch (IndexOutOfBoundsException e) {
// Should never happen because this code gets the counter name from the same
// include file as the BPF program that increments the counter.
Log.wtf(TAG, "Unknown tethering counter type " + k.val);
counterName = Long.toString(k.val);
}
if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
});
} catch (ErrnoException e) {
pw.println("Error dumping counter map: " + e);
}
}
/** IPv6 forwarding rule class. */
public static class Ipv6ForwardingRule {
public final int upstreamIfindex;
@@ -1296,4 +1344,6 @@ public class BpfCoordinator {
final SparseArray<String> getInterfaceNamesForTesting() {
return mInterfaceNames;
}
private static native String[] getBpfCounterNames();
}

View File

@@ -69,6 +69,7 @@ java_defaults {
// For mockito extended
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
"libtetherutilsjni",
],
}