Monitor interface added and update bpf interface map

Have BpfInterfaceMapUpdater to update bpf interface map: adding
the interface and index mapping to bpf interface map when interface
added.

Bug: 215095957
Test: atest FrameworkNetTests

Change-Id: I2189a50c4869cfc0c33fc6f0228f40ee9f3ac1d4
This commit is contained in:
markchien
2022-01-18 18:26:28 +08:00
parent 37c0e499dc
commit e1825f1789
5 changed files with 251 additions and 0 deletions

View File

@@ -26,6 +26,8 @@ filegroup {
srcs: [
"src/com/android/server/net/NetworkIdentity*.java",
"src/com/android/server/net/NetworkStats*.java",
"src/com/android/server/net/BpfInterfaceMapUpdater.java",
"src/com/android/server/net/InterfaceMapValue.java",
],
path: "src",
visibility: [
@@ -97,3 +99,28 @@ filegroup {
"//packages/modules/Connectivity:__subpackages__",
],
}
cc_library_shared {
name: "libcom_android_net_module_util_jni",
min_sdk_version: "30",
cflags: [
"-Wall",
"-Werror",
"-Wno-unused-parameter",
"-Wthread-safety",
],
srcs: [
"jni/onload.cpp",
],
stl: "libc++_static",
static_libs: [
"libnet_utils_device_common_bpfjni",
],
shared_libs: [
"liblog",
"libnativehelper",
],
apex_available: [
"//apex_available:platform",
],
}

38
service-t/jni/onload.cpp Normal file
View File

@@ -0,0 +1,38 @@
/*
* 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 <nativehelper/JNIHelp.h>
#include <log/log.h>
namespace android {
int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
ALOGE("GetEnv failed");
return JNI_ERR;
}
if (register_com_android_net_module_util_BpfMap(env,
"com/android/net/module/util/BpfMap") < 0) return JNI_ERR;
return JNI_VERSION_1_6;
}
};

View File

@@ -0,0 +1,139 @@
/*
* 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.server.net;
import android.content.Context;
import android.net.INetd;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.system.ErrnoException;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.Struct.U32;
/**
* Monitor interface added (without removed) and right interface name and its index to bpf map.
*/
public class BpfInterfaceMapUpdater {
private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName();
// This is current path but may be changed soon.
private static final String IFACE_INDEX_NAME_MAP_PATH =
"/sys/fs/bpf/map_netd_iface_index_name_map";
private final IBpfMap<U32, InterfaceMapValue> mBpfMap;
private final INetd mNetd;
private final Handler mHandler;
private final Dependencies mDeps;
public BpfInterfaceMapUpdater(Context ctx, Handler handler) {
this(ctx, handler, new Dependencies());
}
@VisibleForTesting
public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) {
mDeps = deps;
mBpfMap = deps.getInterfaceMap();
mNetd = deps.getINetd(ctx);
mHandler = handler;
}
/**
* Dependencies of BpfInerfaceMapUpdater, for injection in tests.
*/
@VisibleForTesting
public static class Dependencies {
/** Create BpfMap for updating interface and index mapping. */
public IBpfMap<U32, InterfaceMapValue> getInterfaceMap() {
try {
return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR,
U32.class, InterfaceMapValue.class);
} catch (ErrnoException e) {
Log.e(TAG, "Cannot create interface map: " + e);
return null;
}
}
/** Get InterfaceParams for giving interface name. */
public InterfaceParams getInterfaceParams(String ifaceName) {
return InterfaceParams.getByName(ifaceName);
}
/** Get INetd binder object. */
public INetd getINetd(Context ctx) {
return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE));
}
}
/**
* Start listening interface update event.
* Query current interface names before listening.
*/
public void start() {
mHandler.post(() -> {
if (mBpfMap == null) {
Log.wtf(TAG, "Fail to start: Null bpf map");
return;
}
try {
// TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead.
mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver());
} catch (RemoteException e) {
Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e);
}
final String[] ifaces;
try {
// TODO: use a netlink dump to get the current interface list.
ifaces = mNetd.interfaceGetList();
} catch (RemoteException | ServiceSpecificException e) {
Log.wtf(TAG, "Unable to query interface names by netd, " + e);
return;
}
for (String ifaceName : ifaces) {
addInterface(ifaceName);
}
});
}
private void addInterface(String ifaceName) {
final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName);
if (iface == null) {
Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName);
return;
}
try {
mBpfMap.updateEntry(new U32(iface.index), new InterfaceMapValue(ifaceName));
} catch (ErrnoException e) {
Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e);
}
}
private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener {
@Override
public void onInterfaceAdded(String ifName) {
mHandler.post(() -> addInterface(ifName));
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2020 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.server.net;
import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
/**
* The value of bpf interface index map which is used for NetworkStatsService.
*/
public class InterfaceMapValue extends Struct {
@Field(order = 0, type = Type.ByteArray, arraysize = 16)
public final byte[] interfaceName;
public InterfaceMapValue(String iface) {
final byte[] ifaceArray = iface.getBytes();
interfaceName = new byte[16];
// All array bytes after the interface name, if any, must be 0.
System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length);
}
}

View File

@@ -356,6 +356,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@NonNull
private final LocationPermissionChecker mLocationPermissionChecker;
@NonNull
private final BpfInterfaceMapUpdater mInterfaceMapUpdater;
private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
@@ -453,6 +456,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
mNetworkStatsSubscriptionsMonitor);
mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler);
mInterfaceMapUpdater.start();
}
/**
@@ -507,6 +512,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public LocationPermissionChecker makeLocationPermissionChecker(final Context context) {
return new LocationPermissionChecker(context);
}
/** Create BpfInterfaceMapUpdater to update bpf interface map. */
@NonNull
public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater(
@NonNull Context ctx, @NonNull Handler handler) {
return new BpfInterfaceMapUpdater(ctx, handler);
}
}
/**