Use eBPF map data for per iface stats

After adding the xt_bpf module and ifaceStatsMap, eBPF tool can now
support reading per interface data. So networkStatsFactory should move
away from parsing proc/net/dev and use the eBPF map stats instead.

Bug: 72111305
Test: atest com.android.server.net.NetworkStatsServiceTest
Change-Id: Ibcc6150d00835b3bd33af22a72e4a86e172581cf
This commit is contained in:
Chenbo Feng
2018-04-18 15:44:46 -07:00
parent 78652232dd
commit 2dc99dc445
2 changed files with 63 additions and 37 deletions

View File

@@ -176,6 +176,14 @@ public class NetworkStatsFactory {
return stats;
}
public NetworkStats readBpfNetworkStatsDev() throws IOException {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
if (nativeReadNetworkStatsDev(stats) != 0) {
throw new IOException("Failed to parse bpf iface stats");
}
return stats;
}
/**
* Parse and return interface-level summary {@link NetworkStats} measured
* using {@code /proc/net/dev} style hooks, which may include non IP layer
@@ -186,9 +194,9 @@ public class NetworkStatsFactory {
*/
public NetworkStats readNetworkStatsSummaryDev() throws IOException {
// Return the stats get from /proc/net/dev if switched to bpf module.
// Return xt_bpf stats if switched to bpf module.
if (mUseBpfStats)
return readNetworkStatsIfaceDev();
return readBpfNetworkStatsDev();
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
@@ -242,9 +250,9 @@ public class NetworkStatsFactory {
*/
public NetworkStats readNetworkStatsSummaryXt() throws IOException {
// Return the stats get from /proc/net/dev if qtaguid module is replaced.
// Return xt_bpf stats if qtaguid module is replaced.
if (mUseBpfStats)
return readNetworkStatsIfaceDev();
return readBpfNetworkStatsDev();
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
@@ -406,4 +414,7 @@ public class NetworkStatsFactory {
@VisibleForTesting
public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
@VisibleForTesting
public static native int nativeReadNetworkStatsDev(NetworkStats stats);
}

View File

@@ -205,37 +205,8 @@ static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
return 0;
}
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
jboolean useBpfStats) {
ScopedUtfChars path8(env, path);
if (path8.c_str() == NULL) {
return -1;
}
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
int num = env->GetArrayLength(limitIfacesObj);
for (int i = 0; i < num; i++) {
jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
ScopedUtfChars string8(env, string);
if (string8.c_str() != NULL) {
limitIfaces.push_back(std::string(string8.c_str()));
}
}
}
std::vector<stats_line> lines;
if (useBpfStats) {
if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
return -1;
} else {
if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
limitUid, path8.c_str()) < 0)
return -1;
}
static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
std::vector<stats_line>& lines) {
int size = lines.size();
bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
@@ -308,14 +279,58 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr
env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
}
return 0;
}
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
jboolean useBpfStats) {
ScopedUtfChars path8(env, path);
if (path8.c_str() == NULL) {
return -1;
}
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
int num = env->GetArrayLength(limitIfacesObj);
for (int i = 0; i < num; i++) {
jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
ScopedUtfChars string8(env, string);
if (string8.c_str() != NULL) {
limitIfaces.push_back(std::string(string8.c_str()));
}
}
}
std::vector<stats_line> lines;
if (useBpfStats) {
if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
return -1;
} else {
if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
limitUid, path8.c_str()) < 0)
return -1;
}
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) {
std::vector<stats_line> lines;
if (parseBpfNetworkStatsDev(&lines) < 0)
return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
"(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
(void*) readNetworkStatsDetail }
(void*) readNetworkStatsDetail },
{ "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDev },
};
int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {