Merge "[NFCT.TETHER.2] Migrate tetherOffloadRuleAdd from netd to mainline" am: 6bc18e6d2c am: 79f0ca8849
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1536562 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I9e3adfd593a190d97a72d591359e06d6a31d0bde
This commit is contained in:
@@ -19,6 +19,7 @@ java_defaults {
|
|||||||
sdk_version: "module_current",
|
sdk_version: "module_current",
|
||||||
min_sdk_version: "30",
|
min_sdk_version: "30",
|
||||||
srcs: [
|
srcs: [
|
||||||
|
"apishim/**/*.java",
|
||||||
"src/**/*.java",
|
"src/**/*.java",
|
||||||
":framework-tethering-shared-srcs",
|
":framework-tethering-shared-srcs",
|
||||||
":tethering-module-utils-srcs",
|
":tethering-module-utils-srcs",
|
||||||
@@ -26,6 +27,7 @@ java_defaults {
|
|||||||
],
|
],
|
||||||
static_libs: [
|
static_libs: [
|
||||||
"androidx.annotation_annotation",
|
"androidx.annotation_annotation",
|
||||||
|
"modules-utils-build",
|
||||||
"netlink-client",
|
"netlink-client",
|
||||||
// TODO: use networkstack-client instead of just including the AIDL interface
|
// TODO: use networkstack-client instead of just including the AIDL interface
|
||||||
"networkstack-aidl-interfaces-unstable-java",
|
"networkstack-aidl-interfaces-unstable-java",
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.networkstack.tethering.apishim.api30;
|
||||||
|
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceSpecificException;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bpf coordinator class for API shims.
|
||||||
|
*/
|
||||||
|
public class BpfCoordinatorShimImpl
|
||||||
|
extends com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim {
|
||||||
|
private static final String TAG = "api30.BpfCoordinatorShimImpl";
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final SharedLog mLog;
|
||||||
|
@NonNull
|
||||||
|
private final INetd mNetd;
|
||||||
|
|
||||||
|
public BpfCoordinatorShimImpl(@NonNull final Dependencies deps) {
|
||||||
|
mLog = deps.getSharedLog().forSubComponent(TAG);
|
||||||
|
mNetd = deps.getNetd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tetherOffloadRuleAdd(@NonNull final Ipv6ForwardingRule rule) {
|
||||||
|
try {
|
||||||
|
mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
|
||||||
|
} catch (RemoteException | ServiceSpecificException e) {
|
||||||
|
mLog.e("Could not add IPv6 forwarding rule: ", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Netd used";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.networkstack.tethering.apishim.api31;
|
||||||
|
|
||||||
|
import android.net.util.SharedLog;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
|
import com.android.networkstack.tethering.BpfMap;
|
||||||
|
import com.android.networkstack.tethering.TetherIngressKey;
|
||||||
|
import com.android.networkstack.tethering.TetherIngressValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bpf coordinator class for API shims.
|
||||||
|
*/
|
||||||
|
public class BpfCoordinatorShimImpl
|
||||||
|
extends com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim {
|
||||||
|
private static final String TAG = "api31.BpfCoordinatorShimImpl";
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final SharedLog mLog;
|
||||||
|
|
||||||
|
// BPF map of ingress queueing discipline which pre-processes the packets by the IPv6
|
||||||
|
// forwarding rules.
|
||||||
|
@Nullable
|
||||||
|
private final BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
|
||||||
|
|
||||||
|
public BpfCoordinatorShimImpl(@NonNull final Dependencies deps) {
|
||||||
|
mLog = deps.getSharedLog().forSubComponent(TAG);
|
||||||
|
mBpfIngressMap = deps.getBpfIngressMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return mBpfIngressMap != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tetherOffloadRuleAdd(@NonNull final Ipv6ForwardingRule rule) {
|
||||||
|
if (!isInitialized()) return false;
|
||||||
|
|
||||||
|
final TetherIngressKey key = rule.makeTetherIngressKey();
|
||||||
|
final TetherIngressValue value = rule.makeTetherIngressValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
mBpfIngressMap.updateEntry(key, value);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
mLog.e("Could not update entry: ", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "mBpfIngressMap{"
|
||||||
|
+ (mBpfIngressMap != null ? "initialized" : "not initialized") + "} "
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.networkstack.tethering.apishim.common;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
||||||
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bpf coordinator class for API shims.
|
||||||
|
*/
|
||||||
|
public abstract class BpfCoordinatorShim {
|
||||||
|
/**
|
||||||
|
* Get BpfCoordinatorShim object by OS build version.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static BpfCoordinatorShim getBpfCoordinatorShim(@NonNull final Dependencies deps) {
|
||||||
|
if (deps.isAtLeastS()) {
|
||||||
|
return new com.android.networkstack.tethering.apishim.api31.BpfCoordinatorShimImpl(
|
||||||
|
deps);
|
||||||
|
} else {
|
||||||
|
return new com.android.networkstack.tethering.apishim.api30.BpfCoordinatorShimImpl(
|
||||||
|
deps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this class has been initialized, otherwise return false.
|
||||||
|
*/
|
||||||
|
public abstract boolean isInitialized();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a tethering offload rule to BPF map, or updates it if it already exists.
|
||||||
|
*
|
||||||
|
* Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated
|
||||||
|
* if the input interface and destination prefix match. Otherwise, a new rule will be created.
|
||||||
|
* Note that this can be only called on handler thread.
|
||||||
|
*
|
||||||
|
* @param rule The rule to add or update.
|
||||||
|
*/
|
||||||
|
public abstract boolean tetherOffloadRuleAdd(@NonNull Ipv6ForwardingRule rule);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ import static android.net.NetworkStats.TAG_NONE;
|
|||||||
import static android.net.NetworkStats.UID_ALL;
|
import static android.net.NetworkStats.UID_ALL;
|
||||||
import static android.net.NetworkStats.UID_TETHERING;
|
import static android.net.NetworkStats.UID_TETHERING;
|
||||||
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
||||||
|
import static android.system.OsConstants.ETH_P_IPV6;
|
||||||
|
|
||||||
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
|
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ import android.os.ConditionVariable;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceSpecificException;
|
import android.os.ServiceSpecificException;
|
||||||
|
import android.system.ErrnoException;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -51,6 +53,9 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
import com.android.modules.utils.build.SdkLevel;
|
||||||
|
import com.android.net.module.util.NetworkStackConstants;
|
||||||
|
import com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim;
|
||||||
|
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -71,6 +76,8 @@ import java.util.Objects;
|
|||||||
public class BpfCoordinator {
|
public class BpfCoordinator {
|
||||||
private static final String TAG = BpfCoordinator.class.getSimpleName();
|
private static final String TAG = BpfCoordinator.class.getSimpleName();
|
||||||
private static final int DUMP_TIMEOUT_MS = 10_000;
|
private static final int DUMP_TIMEOUT_MS = 10_000;
|
||||||
|
private static final String TETHER_INGRESS_FS_PATH =
|
||||||
|
"/sys/fs/bpf/map_offload_tether_ingress_map";
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
enum StatsType {
|
enum StatsType {
|
||||||
@@ -88,6 +95,8 @@ public class BpfCoordinator {
|
|||||||
private final Dependencies mDeps;
|
private final Dependencies mDeps;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final BpfTetherStatsProvider mStatsProvider;
|
private final BpfTetherStatsProvider mStatsProvider;
|
||||||
|
@NonNull
|
||||||
|
private final BpfCoordinatorShim mBpfCoordinatorShim;
|
||||||
|
|
||||||
// True if BPF offload is supported, false otherwise. The BPF offload could be disabled by
|
// True if BPF offload is supported, false otherwise. The BPF offload could be disabled by
|
||||||
// a runtime resource overlay package or device configuration. This flag is only initialized
|
// a runtime resource overlay package or device configuration. This flag is only initialized
|
||||||
@@ -168,6 +177,28 @@ public class BpfCoordinator {
|
|||||||
|
|
||||||
/** Get tethering configuration. */
|
/** Get tethering configuration. */
|
||||||
@Nullable public abstract TetheringConfiguration getTetherConfig();
|
@Nullable public abstract TetheringConfiguration getTetherConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check OS Build at least S.
|
||||||
|
*
|
||||||
|
* TODO: move to BpfCoordinatorShim once the test doesn't need the mocked OS build for
|
||||||
|
* testing different code flows concurrently.
|
||||||
|
*/
|
||||||
|
public boolean isAtLeastS() {
|
||||||
|
// TODO: consider using ShimUtils.isAtLeastS.
|
||||||
|
return SdkLevel.isAtLeastS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get ingress BPF map. */
|
||||||
|
@Nullable public BpfMap<TetherIngressKey, TetherIngressValue> getBpfIngressMap() {
|
||||||
|
try {
|
||||||
|
return new BpfMap<>(TETHER_INGRESS_FS_PATH,
|
||||||
|
BpfMap.BPF_F_RDWR, TetherIngressKey.class, TetherIngressValue.class);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
Log.e(TAG, "Cannot create ingress map: " + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -188,6 +219,11 @@ public class BpfCoordinator {
|
|||||||
provider = null;
|
provider = null;
|
||||||
}
|
}
|
||||||
mStatsProvider = provider;
|
mStatsProvider = provider;
|
||||||
|
|
||||||
|
mBpfCoordinatorShim = BpfCoordinatorShim.getBpfCoordinatorShim(deps);
|
||||||
|
if (!mBpfCoordinatorShim.isInitialized()) {
|
||||||
|
mLog.e("Bpf shim not initialized");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,8 +235,8 @@ public class BpfCoordinator {
|
|||||||
public void startPolling() {
|
public void startPolling() {
|
||||||
if (mPollingStarted) return;
|
if (mPollingStarted) return;
|
||||||
|
|
||||||
if (!mIsBpfEnabled) {
|
if (!isUsingBpf()) {
|
||||||
mLog.i("Offload disabled");
|
mLog.i("BPF is not using");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +267,10 @@ public class BpfCoordinator {
|
|||||||
mLog.i("Polling stopped");
|
mLog.i("Polling stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isUsingBpf() {
|
||||||
|
return mIsBpfEnabled && mBpfCoordinatorShim.isInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add forwarding rule. After adding the first rule on a given upstream, must add the data
|
* Add forwarding rule. After adding the first rule on a given upstream, must add the data
|
||||||
* limit on the given upstream.
|
* limit on the given upstream.
|
||||||
@@ -238,15 +278,10 @@ public class BpfCoordinator {
|
|||||||
*/
|
*/
|
||||||
public void tetherOffloadRuleAdd(
|
public void tetherOffloadRuleAdd(
|
||||||
@NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
|
@NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
|
||||||
if (!mIsBpfEnabled) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
try {
|
// TODO: Perhaps avoid to add a duplicate rule.
|
||||||
// TODO: Perhaps avoid to add a duplicate rule.
|
if (!mBpfCoordinatorShim.tetherOffloadRuleAdd(rule)) return;
|
||||||
mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
|
|
||||||
} catch (RemoteException | ServiceSpecificException e) {
|
|
||||||
mLog.e("Could not add IPv6 forwarding rule: ", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mIpv6ForwardingRules.containsKey(ipServer)) {
|
if (!mIpv6ForwardingRules.containsKey(ipServer)) {
|
||||||
mIpv6ForwardingRules.put(ipServer, new LinkedHashMap<Inet6Address,
|
mIpv6ForwardingRules.put(ipServer, new LinkedHashMap<Inet6Address,
|
||||||
@@ -279,7 +314,7 @@ public class BpfCoordinator {
|
|||||||
*/
|
*/
|
||||||
public void tetherOffloadRuleRemove(
|
public void tetherOffloadRuleRemove(
|
||||||
@NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
|
@NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
|
||||||
if (!mIsBpfEnabled) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Perhaps avoid to remove a non-existent rule.
|
// TODO: Perhaps avoid to remove a non-existent rule.
|
||||||
@@ -324,7 +359,7 @@ public class BpfCoordinator {
|
|||||||
* Note that this can be only called on handler thread.
|
* Note that this can be only called on handler thread.
|
||||||
*/
|
*/
|
||||||
public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
|
public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
|
||||||
if (!mIsBpfEnabled) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
|
final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
|
||||||
ipServer);
|
ipServer);
|
||||||
@@ -341,7 +376,7 @@ public class BpfCoordinator {
|
|||||||
* Note that this can be only called on handler thread.
|
* Note that this can be only called on handler thread.
|
||||||
*/
|
*/
|
||||||
public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
|
public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
|
||||||
if (!mIsBpfEnabled) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
|
final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
|
||||||
ipServer);
|
ipServer);
|
||||||
@@ -365,7 +400,7 @@ public class BpfCoordinator {
|
|||||||
* Note that this can be only called on handler thread.
|
* Note that this can be only called on handler thread.
|
||||||
*/
|
*/
|
||||||
public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
|
public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
|
||||||
if (!mIsBpfEnabled) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
|
if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
|
||||||
|
|
||||||
@@ -396,6 +431,7 @@ public class BpfCoordinator {
|
|||||||
? "registered" : "not registered"));
|
? "registered" : "not registered"));
|
||||||
pw.println("Upstream quota: " + mInterfaceQuotas.toString());
|
pw.println("Upstream quota: " + mInterfaceQuotas.toString());
|
||||||
pw.println("Polling interval: " + getPollingInterval() + " ms");
|
pw.println("Polling interval: " + getPollingInterval() + " ms");
|
||||||
|
pw.println("Bpf shim: " + mBpfCoordinatorShim.toString());
|
||||||
|
|
||||||
pw.println("Forwarding stats:");
|
pw.println("Forwarding stats:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
@@ -497,6 +533,23 @@ public class BpfCoordinator {
|
|||||||
return parcel;
|
return parcel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a TetherIngressKey object built from the rule.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public TetherIngressKey makeTetherIngressKey() {
|
||||||
|
return new TetherIngressKey(upstreamIfindex, address.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a TetherIngressValue object built from the rule.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public TetherIngressValue makeTetherIngressValue() {
|
||||||
|
return new TetherIngressValue(downstreamIfindex, dstMac, srcMac, ETH_P_IPV6,
|
||||||
|
NetworkStackConstants.ETHER_MTU);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof Ipv6ForwardingRule)) return false;
|
if (!(o instanceof Ipv6ForwardingRule)) return false;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import static android.net.netlink.NetlinkConstants.RTM_NEWNEIGH;
|
|||||||
import static android.net.netlink.StructNdMsg.NUD_FAILED;
|
import static android.net.netlink.StructNdMsg.NUD_FAILED;
|
||||||
import static android.net.netlink.StructNdMsg.NUD_REACHABLE;
|
import static android.net.netlink.StructNdMsg.NUD_REACHABLE;
|
||||||
import static android.net.netlink.StructNdMsg.NUD_STALE;
|
import static android.net.netlink.StructNdMsg.NUD_STALE;
|
||||||
|
import static android.system.OsConstants.ETH_P_IPV6;
|
||||||
|
|
||||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
||||||
|
|
||||||
@@ -98,9 +99,13 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.NetworkStackConstants;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator;
|
import com.android.networkstack.tethering.BpfCoordinator;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
|
import com.android.networkstack.tethering.BpfMap;
|
||||||
import com.android.networkstack.tethering.PrivateAddressCoordinator;
|
import com.android.networkstack.tethering.PrivateAddressCoordinator;
|
||||||
|
import com.android.networkstack.tethering.TetherIngressKey;
|
||||||
|
import com.android.networkstack.tethering.TetherIngressValue;
|
||||||
import com.android.networkstack.tethering.TetheringConfiguration;
|
import com.android.networkstack.tethering.TetheringConfiguration;
|
||||||
import com.android.testutils.DevSdkIgnoreRule;
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
@@ -163,6 +168,7 @@ public class IpServerTest {
|
|||||||
@Mock private PrivateAddressCoordinator mAddressCoordinator;
|
@Mock private PrivateAddressCoordinator mAddressCoordinator;
|
||||||
@Mock private NetworkStatsManager mStatsManager;
|
@Mock private NetworkStatsManager mStatsManager;
|
||||||
@Mock private TetheringConfiguration mTetherConfig;
|
@Mock private TetheringConfiguration mTetherConfig;
|
||||||
|
@Mock private BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
|
||||||
|
|
||||||
@Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
|
@Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
|
||||||
|
|
||||||
@@ -173,6 +179,7 @@ public class IpServerTest {
|
|||||||
private InterfaceConfigurationParcel mInterfaceConfiguration;
|
private InterfaceConfigurationParcel mInterfaceConfiguration;
|
||||||
private NeighborEventConsumer mNeighborEventConsumer;
|
private NeighborEventConsumer mNeighborEventConsumer;
|
||||||
private BpfCoordinator mBpfCoordinator;
|
private BpfCoordinator mBpfCoordinator;
|
||||||
|
private BpfCoordinator.Dependencies mBpfDeps;
|
||||||
|
|
||||||
private void initStateMachine(int interfaceType) throws Exception {
|
private void initStateMachine(int interfaceType) throws Exception {
|
||||||
initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
|
initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
|
||||||
@@ -256,8 +263,7 @@ public class IpServerTest {
|
|||||||
mTestAddress);
|
mTestAddress);
|
||||||
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */);
|
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */);
|
||||||
|
|
||||||
mBpfCoordinator = spy(new BpfCoordinator(
|
mBpfDeps = new BpfCoordinator.Dependencies() {
|
||||||
new BpfCoordinator.Dependencies() {
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Handler getHandler() {
|
public Handler getHandler() {
|
||||||
return new Handler(mLooper.getLooper());
|
return new Handler(mLooper.getLooper());
|
||||||
@@ -282,7 +288,13 @@ public class IpServerTest {
|
|||||||
public TetheringConfiguration getTetherConfig() {
|
public TetheringConfiguration getTetherConfig() {
|
||||||
return mTetherConfig;
|
return mTetherConfig;
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
|
@Nullable
|
||||||
|
public BpfMap<TetherIngressKey, TetherIngressValue> getBpfIngressMap() {
|
||||||
|
return mBpfIngressMap;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mBpfCoordinator = spy(new BpfCoordinator(mBpfDeps));
|
||||||
|
|
||||||
setUpDhcpServer();
|
setUpDhcpServer();
|
||||||
}
|
}
|
||||||
@@ -741,6 +753,55 @@ public class IpServerTest {
|
|||||||
(Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac);
|
(Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static TetherIngressKey makeIngressKey(int upstreamIfindex,
|
||||||
|
@NonNull final InetAddress dst) {
|
||||||
|
return new TetherIngressKey(upstreamIfindex, dst.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static TetherIngressValue makeIngressValue(@NonNull final MacAddress dstMac) {
|
||||||
|
return new TetherIngressValue(TEST_IFACE_PARAMS.index, dstMac, TEST_IFACE_PARAMS.macAddr,
|
||||||
|
ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T verifyWithOrder(@Nullable InOrder inOrder, @NonNull T t) {
|
||||||
|
if (inOrder != null) {
|
||||||
|
return inOrder.verify(t);
|
||||||
|
} else {
|
||||||
|
return verify(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyTetherOffloadRuleAdd(@Nullable InOrder inOrder, int upstreamIfindex,
|
||||||
|
@NonNull final InetAddress dst, @NonNull final MacAddress dstMac) throws Exception {
|
||||||
|
if (mBpfDeps.isAtLeastS()) {
|
||||||
|
verifyWithOrder(inOrder, mBpfIngressMap).updateEntry(
|
||||||
|
makeIngressKey(upstreamIfindex, dst), makeIngressValue(dstMac));
|
||||||
|
} else {
|
||||||
|
verifyWithOrder(inOrder, mNetd).tetherOffloadRuleAdd(matches(upstreamIfindex, dst,
|
||||||
|
dstMac));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyNeverTetherOffloadRuleAdd(int upstreamIfindex,
|
||||||
|
@NonNull final InetAddress dst, @NonNull final MacAddress dstMac) throws Exception {
|
||||||
|
if (mBpfDeps.isAtLeastS()) {
|
||||||
|
verify(mBpfIngressMap, never()).updateEntry(makeIngressKey(upstreamIfindex, dst),
|
||||||
|
makeIngressValue(dstMac));
|
||||||
|
} else {
|
||||||
|
verify(mNetd, never()).tetherOffloadRuleAdd(matches(upstreamIfindex, dst, dstMac));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyNeverTetherOffloadRuleAdd() throws Exception {
|
||||||
|
if (mBpfDeps.isAtLeastS()) {
|
||||||
|
verify(mBpfIngressMap, never()).updateEntry(any(), any());
|
||||||
|
} else {
|
||||||
|
verify(mNetd, never()).tetherOffloadRuleAdd(any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) {
|
private static TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) {
|
||||||
TetherStatsParcel parcel = new TetherStatsParcel();
|
TetherStatsParcel parcel = new TetherStatsParcel();
|
||||||
@@ -748,8 +809,8 @@ public class IpServerTest {
|
|||||||
return parcel;
|
return parcel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetNetdAndBpfCoordinator() throws Exception {
|
private void resetNetdBpfMapAndCoordinator() throws Exception {
|
||||||
reset(mNetd, mBpfCoordinator);
|
reset(mNetd, mBpfIngressMap, mBpfCoordinator);
|
||||||
when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
|
when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
|
||||||
when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX))
|
when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX))
|
||||||
.thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX));
|
.thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX));
|
||||||
@@ -774,34 +835,34 @@ public class IpServerTest {
|
|||||||
final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
|
final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
|
||||||
final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
|
final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
|
||||||
|
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
verifyNoMoreInteractions(mBpfCoordinator, mNetd);
|
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfIngressMap);
|
||||||
|
|
||||||
// TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and
|
// TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and
|
||||||
// tetherOffloadGetAndClearStats in netd while the rules are changed.
|
// tetherOffloadGetAndClearStats in netd while the rules are changed.
|
||||||
|
|
||||||
// Events on other interfaces are ignored.
|
// Events on other interfaces are ignored.
|
||||||
recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
|
recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
|
||||||
verifyNoMoreInteractions(mBpfCoordinator, mNetd);
|
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfIngressMap);
|
||||||
|
|
||||||
// Events on this interface are received and sent to netd.
|
// Events on this interface are received and sent to netd.
|
||||||
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighA, macA);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// Link-local and multicast neighbors are ignored.
|
// Link-local and multicast neighbors are ignored.
|
||||||
recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
|
||||||
verifyNoMoreInteractions(mBpfCoordinator, mNetd);
|
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfIngressMap);
|
||||||
recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
|
||||||
verifyNoMoreInteractions(mBpfCoordinator, mNetd);
|
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfIngressMap);
|
||||||
|
|
||||||
// A neighbor that is no longer valid causes the rule to be removed.
|
// A neighbor that is no longer valid causes the rule to be removed.
|
||||||
// NUD_FAILED events do not have a MAC address.
|
// NUD_FAILED events do not have a MAC address.
|
||||||
@@ -809,30 +870,30 @@ public class IpServerTest {
|
|||||||
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull));
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull));
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// A neighbor that is deleted causes the rule to be removed.
|
// A neighbor that is deleted causes the rule to be removed.
|
||||||
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
|
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull));
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull));
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// Upstream changes result in updating the rules.
|
// Upstream changes result in updating the rules.
|
||||||
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
||||||
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
InOrder inOrder = inOrder(mNetd);
|
InOrder inOrder = inOrder(mNetd, mBpfIngressMap);
|
||||||
LinkProperties lp = new LinkProperties();
|
LinkProperties lp = new LinkProperties();
|
||||||
lp.setInterfaceName(UPSTREAM_IFACE2);
|
lp.setInterfaceName(UPSTREAM_IFACE2);
|
||||||
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
|
verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
|
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
|
verifyTetherOffloadRuleAdd(inOrder, UPSTREAM_IFINDEX2, neighA, macA);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
|
verifyTetherOffloadRuleAdd(inOrder, UPSTREAM_IFINDEX2, neighB, macB);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// When the upstream is lost, rules are removed.
|
// When the upstream is lost, rules are removed.
|
||||||
dispatchTetherConnectionChanged(null, null, 0);
|
dispatchTetherConnectionChanged(null, null, 0);
|
||||||
@@ -843,15 +904,15 @@ public class IpServerTest {
|
|||||||
verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
|
verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// If the upstream is IPv4-only, no rules are added.
|
// If the upstream is IPv4-only, no rules are added.
|
||||||
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
|
||||||
// Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost.
|
// Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost.
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
|
verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
|
||||||
verifyNoMoreInteractions(mBpfCoordinator, mNetd);
|
verifyNoMoreInteractions(mBpfCoordinator, mNetd, mBpfIngressMap);
|
||||||
|
|
||||||
// Rules can be added again once upstream IPv6 connectivity is available.
|
// Rules can be added again once upstream IPv6 connectivity is available.
|
||||||
lp.setInterfaceName(UPSTREAM_IFACE);
|
lp.setInterfaceName(UPSTREAM_IFACE);
|
||||||
@@ -859,13 +920,13 @@ public class IpServerTest {
|
|||||||
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
|
||||||
verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
||||||
verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
|
verifyNeverTetherOffloadRuleAdd(UPSTREAM_IFINDEX, neighA, macA);
|
||||||
|
|
||||||
// If upstream IPv6 connectivity is lost, rules are removed.
|
// If upstream IPv6 connectivity is lost, rules are removed.
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
|
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
|
verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
@@ -877,11 +938,11 @@ public class IpServerTest {
|
|||||||
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighA, macA);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neighB, macB);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
mIpServer.stop();
|
mIpServer.stop();
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
@@ -889,7 +950,7 @@ public class IpServerTest {
|
|||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
|
||||||
verify(mIpNeighborMonitor).stop();
|
verify(mIpNeighborMonitor).stop();
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -910,35 +971,35 @@ public class IpServerTest {
|
|||||||
// A neighbor that is added or deleted causes the rule to be added or removed.
|
// A neighbor that is added or deleted causes the rule to be added or removed.
|
||||||
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
|
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
|
||||||
true /* usingBpfOffload */);
|
true /* usingBpfOffload */);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
verify(mBpfCoordinator).tetherOffloadRuleAdd(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA));
|
||||||
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
|
verifyTetherOffloadRuleAdd(null, UPSTREAM_IFINDEX, neigh, macA);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
|
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
|
||||||
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
verify(mBpfCoordinator).tetherOffloadRuleRemove(
|
||||||
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull));
|
mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull));
|
||||||
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
|
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
// [2] Disable BPF offload.
|
// [2] Disable BPF offload.
|
||||||
// A neighbor that is added or deleted doesn’t cause the rule to be added or removed.
|
// A neighbor that is added or deleted doesn’t cause the rule to be added or removed.
|
||||||
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
|
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
|
||||||
false /* usingBpfOffload */);
|
false /* usingBpfOffload */);
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
|
recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
|
||||||
verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any());
|
verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any());
|
||||||
verify(mNetd, never()).tetherOffloadRuleAdd(any());
|
verifyNeverTetherOffloadRuleAdd();
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
|
|
||||||
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
|
recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
|
||||||
verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any());
|
verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any());
|
||||||
verify(mNetd, never()).tetherOffloadRuleRemove(any());
|
verify(mNetd, never()).tetherOffloadRuleRemove(any());
|
||||||
resetNetdAndBpfCoordinator();
|
resetNetdBpfMapAndCoordinator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import static android.net.NetworkStats.TAG_NONE;
|
|||||||
import static android.net.NetworkStats.UID_ALL;
|
import static android.net.NetworkStats.UID_ALL;
|
||||||
import static android.net.NetworkStats.UID_TETHERING;
|
import static android.net.NetworkStats.UID_TETHERING;
|
||||||
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
|
||||||
|
import static android.system.OsConstants.ETH_P_IPV6;
|
||||||
|
|
||||||
import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
|
import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
|
||||||
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
|
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
|
||||||
@@ -33,6 +34,7 @@ import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
@@ -40,8 +42,10 @@ import static org.mockito.Matchers.anyLong;
|
|||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Mockito.argThat;
|
import static org.mockito.Mockito.argThat;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -54,6 +58,7 @@ import android.net.TetherOffloadRuleParcel;
|
|||||||
import android.net.TetherStatsParcel;
|
import android.net.TetherStatsParcel;
|
||||||
import android.net.ip.IpServer;
|
import android.net.ip.IpServer;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
|
|
||||||
@@ -62,7 +67,9 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.NetworkStackConstants;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
import com.android.testutils.TestableNetworkStatsProviderCbBinder;
|
import com.android.testutils.TestableNetworkStatsProviderCbBinder;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -94,6 +101,7 @@ public class BpfCoordinatorTest {
|
|||||||
@Mock private INetd mNetd;
|
@Mock private INetd mNetd;
|
||||||
@Mock private IpServer mIpServer;
|
@Mock private IpServer mIpServer;
|
||||||
@Mock private TetheringConfiguration mTetherConfig;
|
@Mock private TetheringConfiguration mTetherConfig;
|
||||||
|
@Mock private BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
|
||||||
|
|
||||||
// Late init since methods must be called by the thread that created this object.
|
// Late init since methods must be called by the thread that created this object.
|
||||||
private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
|
private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
|
||||||
@@ -102,32 +110,37 @@ public class BpfCoordinatorTest {
|
|||||||
ArgumentCaptor.forClass(ArrayList.class);
|
ArgumentCaptor.forClass(ArrayList.class);
|
||||||
private final TestLooper mTestLooper = new TestLooper();
|
private final TestLooper mTestLooper = new TestLooper();
|
||||||
private BpfCoordinator.Dependencies mDeps =
|
private BpfCoordinator.Dependencies mDeps =
|
||||||
new BpfCoordinator.Dependencies() {
|
spy(new BpfCoordinator.Dependencies() {
|
||||||
@NonNull
|
@NonNull
|
||||||
public Handler getHandler() {
|
public Handler getHandler() {
|
||||||
return new Handler(mTestLooper.getLooper());
|
return new Handler(mTestLooper.getLooper());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public INetd getNetd() {
|
public INetd getNetd() {
|
||||||
return mNetd;
|
return mNetd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NetworkStatsManager getNetworkStatsManager() {
|
public NetworkStatsManager getNetworkStatsManager() {
|
||||||
return mStatsManager;
|
return mStatsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public SharedLog getSharedLog() {
|
public SharedLog getSharedLog() {
|
||||||
return new SharedLog("test");
|
return new SharedLog("test");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public TetheringConfiguration getTetherConfig() {
|
public TetheringConfiguration getTetherConfig() {
|
||||||
return mTetherConfig;
|
return mTetherConfig;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
@Nullable
|
||||||
|
public BpfMap<TetherIngressKey, TetherIngressValue> getBpfIngressMap() {
|
||||||
|
return mBpfIngressMap;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@@ -185,6 +198,63 @@ public class BpfCoordinatorTest {
|
|||||||
waitForIdle();
|
waitForIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> T verifyWithOrder(@Nullable InOrder inOrder, @NonNull T t) {
|
||||||
|
if (inOrder != null) {
|
||||||
|
return inOrder.verify(t);
|
||||||
|
} else {
|
||||||
|
return verify(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyTetherOffloadRuleAdd(@Nullable InOrder inOrder,
|
||||||
|
@NonNull Ipv6ForwardingRule rule) throws Exception {
|
||||||
|
if (mDeps.isAtLeastS()) {
|
||||||
|
verifyWithOrder(inOrder, mBpfIngressMap).updateEntry(
|
||||||
|
rule.makeTetherIngressKey(), rule.makeTetherIngressValue());
|
||||||
|
} else {
|
||||||
|
verifyWithOrder(inOrder, mNetd).tetherOffloadRuleAdd(matches(rule));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyNeverTetherOffloadRuleAdd() throws Exception {
|
||||||
|
if (mDeps.isAtLeastS()) {
|
||||||
|
verify(mBpfIngressMap, never()).updateEntry(any(), any());
|
||||||
|
} else {
|
||||||
|
verify(mNetd, never()).tetherOffloadRuleAdd(any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove once presubmit tests on R even the code is submitted on S.
|
||||||
|
private void checkTetherOffloadRuleAdd(boolean usingApiS) throws Exception {
|
||||||
|
setupFunctioningNetdInterface();
|
||||||
|
|
||||||
|
// Replace Dependencies#isAtLeastS() for testing R and S+ BPF map apis. Note that |mDeps|
|
||||||
|
// must be mocked before calling #makeBpfCoordinator which use |mDeps| to initialize the
|
||||||
|
// coordinator.
|
||||||
|
doReturn(usingApiS).when(mDeps).isAtLeastS();
|
||||||
|
final BpfCoordinator coordinator = makeBpfCoordinator();
|
||||||
|
|
||||||
|
final String mobileIface = "rmnet_data0";
|
||||||
|
final Integer mobileIfIndex = 100;
|
||||||
|
coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
|
||||||
|
|
||||||
|
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
||||||
|
coordinator.tetherOffloadRuleAdd(mIpServer, rule);
|
||||||
|
verifyTetherOffloadRuleAdd(null, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove once presubmit tests on R even the code is submitted on S.
|
||||||
|
@Test
|
||||||
|
public void testTetherOffloadRuleAddSdkR() throws Exception {
|
||||||
|
checkTetherOffloadRuleAdd(false /* R */);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove once presubmit tests on R even the code is submitted on S.
|
||||||
|
@Test
|
||||||
|
public void testTetherOffloadRuleAddAtLeastSdkS() throws Exception {
|
||||||
|
checkTetherOffloadRuleAdd(true /* S+ */);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetForwardedStats() throws Exception {
|
public void testGetForwardedStats() throws Exception {
|
||||||
setupFunctioningNetdInterface();
|
setupFunctioningNetdInterface();
|
||||||
@@ -338,6 +408,33 @@ public class BpfCoordinatorTest {
|
|||||||
DOWNSTREAM_MAC, dstMac);
|
DOWNSTREAM_MAC, dstMac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRuleMakeTetherIngressKey() throws Exception {
|
||||||
|
final Integer mobileIfIndex = 100;
|
||||||
|
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
||||||
|
|
||||||
|
final TetherIngressKey key = rule.makeTetherIngressKey();
|
||||||
|
assertEquals(key.iif, (long) mobileIfIndex);
|
||||||
|
assertTrue(Arrays.equals(key.neigh6, NEIGH_A.getAddress()));
|
||||||
|
// iif (4) + neigh6 (16) = 20.
|
||||||
|
assertEquals(20, key.writeToBytes().length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRuleMakeTetherIngressValue() throws Exception {
|
||||||
|
final Integer mobileIfIndex = 100;
|
||||||
|
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
||||||
|
|
||||||
|
final TetherIngressValue value = rule.makeTetherIngressValue();
|
||||||
|
assertEquals(value.oif, DOWNSTREAM_IFINDEX);
|
||||||
|
assertEquals(value.ethDstMac, MAC_A);
|
||||||
|
assertEquals(value.ethSrcMac, DOWNSTREAM_MAC);
|
||||||
|
assertEquals(value.ethProto, ETH_P_IPV6);
|
||||||
|
assertEquals(value.pmtu, NetworkStackConstants.ETHER_MTU);
|
||||||
|
// oif (4) + ethDstMac (6) + ethSrcMac (6) + ethProto (2) + pmtu (2) = 20.
|
||||||
|
assertEquals(20, value.writeToBytes().length);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetDataLimit() throws Exception {
|
public void testSetDataLimit() throws Exception {
|
||||||
setupFunctioningNetdInterface();
|
setupFunctioningNetdInterface();
|
||||||
@@ -352,9 +449,9 @@ public class BpfCoordinatorTest {
|
|||||||
// Set the unlimited quota as default if the service has never applied a data limit for a
|
// Set the unlimited quota as default if the service has never applied a data limit for a
|
||||||
// given upstream. Note that the data limit only be applied on an upstream which has rules.
|
// given upstream. Note that the data limit only be applied on an upstream which has rules.
|
||||||
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
||||||
final InOrder inOrder = inOrder(mNetd);
|
final InOrder inOrder = inOrder(mNetd, mBpfIngressMap);
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, rule);
|
coordinator.tetherOffloadRuleAdd(mIpServer, rule);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(rule));
|
verifyTetherOffloadRuleAdd(inOrder, rule);
|
||||||
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED);
|
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
@@ -393,7 +490,7 @@ public class BpfCoordinatorTest {
|
|||||||
// Applying a data limit to the current upstream does not take any immediate action.
|
// Applying a data limit to the current upstream does not take any immediate action.
|
||||||
// The data limit could be only set on an upstream which has rules.
|
// The data limit could be only set on an upstream which has rules.
|
||||||
final long limit = 12345;
|
final long limit = 12345;
|
||||||
final InOrder inOrder = inOrder(mNetd);
|
final InOrder inOrder = inOrder(mNetd, mBpfIngressMap);
|
||||||
mTetherStatsProvider.onSetLimit(mobileIface, limit);
|
mTetherStatsProvider.onSetLimit(mobileIface, limit);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong());
|
inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong());
|
||||||
@@ -401,14 +498,14 @@ public class BpfCoordinatorTest {
|
|||||||
// Adding the first rule on current upstream immediately sends the quota to netd.
|
// Adding the first rule on current upstream immediately sends the quota to netd.
|
||||||
final Ipv6ForwardingRule ruleA = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
final Ipv6ForwardingRule ruleA = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, ruleA);
|
coordinator.tetherOffloadRuleAdd(mIpServer, ruleA);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ruleA));
|
verifyTetherOffloadRuleAdd(inOrder, ruleA);
|
||||||
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, limit);
|
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, limit);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// Adding the second rule on current upstream does not send the quota to netd.
|
// Adding the second rule on current upstream does not send the quota to netd.
|
||||||
final Ipv6ForwardingRule ruleB = buildTestForwardingRule(mobileIfIndex, NEIGH_B, MAC_B);
|
final Ipv6ForwardingRule ruleB = buildTestForwardingRule(mobileIfIndex, NEIGH_B, MAC_B);
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, ruleB);
|
coordinator.tetherOffloadRuleAdd(mIpServer, ruleB);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ruleB));
|
verifyTetherOffloadRuleAdd(inOrder, ruleB);
|
||||||
inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong());
|
inOrder.verify(mNetd, never()).tetherOffloadSetInterfaceQuota(anyInt(), anyLong());
|
||||||
|
|
||||||
// Removing the second rule on current upstream does not send the quota to netd.
|
// Removing the second rule on current upstream does not send the quota to netd.
|
||||||
@@ -438,7 +535,7 @@ public class BpfCoordinatorTest {
|
|||||||
coordinator.addUpstreamNameToLookupTable(ethIfIndex, ethIface);
|
coordinator.addUpstreamNameToLookupTable(ethIfIndex, ethIface);
|
||||||
coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
|
coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
|
||||||
|
|
||||||
final InOrder inOrder = inOrder(mNetd);
|
final InOrder inOrder = inOrder(mNetd, mBpfIngressMap);
|
||||||
|
|
||||||
// Before the rule test, here are the additional actions while the rules are changed.
|
// Before the rule test, here are the additional actions while the rules are changed.
|
||||||
// - After adding the first rule on a given upstream, the coordinator adds a data limit.
|
// - After adding the first rule on a given upstream, the coordinator adds a data limit.
|
||||||
@@ -455,11 +552,11 @@ public class BpfCoordinatorTest {
|
|||||||
ethIfIndex, NEIGH_B, MAC_B);
|
ethIfIndex, NEIGH_B, MAC_B);
|
||||||
|
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleA);
|
coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleA);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ethernetRuleA));
|
verifyTetherOffloadRuleAdd(inOrder, ethernetRuleA);
|
||||||
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(ethIfIndex, QUOTA_UNLIMITED);
|
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(ethIfIndex, QUOTA_UNLIMITED);
|
||||||
|
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleB);
|
coordinator.tetherOffloadRuleAdd(mIpServer, ethernetRuleB);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(ethernetRuleB));
|
verifyTetherOffloadRuleAdd(inOrder, ethernetRuleB);
|
||||||
|
|
||||||
// [2] Update the existing rules from Ethernet to cellular.
|
// [2] Update the existing rules from Ethernet to cellular.
|
||||||
final Ipv6ForwardingRule mobileRuleA = buildTestForwardingRule(
|
final Ipv6ForwardingRule mobileRuleA = buildTestForwardingRule(
|
||||||
@@ -473,11 +570,11 @@ public class BpfCoordinatorTest {
|
|||||||
// by one for updating upstream interface index by #tetherOffloadRuleUpdate.
|
// by one for updating upstream interface index by #tetherOffloadRuleUpdate.
|
||||||
coordinator.tetherOffloadRuleUpdate(mIpServer, mobileIfIndex);
|
coordinator.tetherOffloadRuleUpdate(mIpServer, mobileIfIndex);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleA));
|
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleA));
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(mobileRuleA));
|
verifyTetherOffloadRuleAdd(inOrder, mobileRuleA);
|
||||||
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED);
|
inOrder.verify(mNetd).tetherOffloadSetInterfaceQuota(mobileIfIndex, QUOTA_UNLIMITED);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleB));
|
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(ethernetRuleB));
|
||||||
inOrder.verify(mNetd).tetherOffloadGetAndClearStats(ethIfIndex);
|
inOrder.verify(mNetd).tetherOffloadGetAndClearStats(ethIfIndex);
|
||||||
inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(mobileRuleB));
|
verifyTetherOffloadRuleAdd(inOrder, mobileRuleB);
|
||||||
|
|
||||||
// [3] Clear all rules for a given IpServer.
|
// [3] Clear all rules for a given IpServer.
|
||||||
when(mNetd.tetherOffloadGetAndClearStats(mobileIfIndex))
|
when(mNetd.tetherOffloadGetAndClearStats(mobileIfIndex))
|
||||||
@@ -499,11 +596,10 @@ public class BpfCoordinatorTest {
|
|||||||
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 50, 60, 70, 80)));
|
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 50, 60, 70, 80)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void checkBpfDisabled() throws Exception {
|
||||||
public void testTetheringConfigDisable() throws Exception {
|
// The caller may mock the global dependencies |mDeps| which is used in
|
||||||
setupFunctioningNetdInterface();
|
// #makeBpfCoordinator for testing.
|
||||||
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(false);
|
// See #testBpfDisabledbyNoBpfIngressMap.
|
||||||
|
|
||||||
final BpfCoordinator coordinator = makeBpfCoordinator();
|
final BpfCoordinator coordinator = makeBpfCoordinator();
|
||||||
coordinator.startPolling();
|
coordinator.startPolling();
|
||||||
|
|
||||||
@@ -523,7 +619,7 @@ public class BpfCoordinatorTest {
|
|||||||
final MacAddress mac = MacAddress.fromString("00:00:00:00:00:0a");
|
final MacAddress mac = MacAddress.fromString("00:00:00:00:00:0a");
|
||||||
final Ipv6ForwardingRule rule = buildTestForwardingRule(ifIndex, neigh, mac);
|
final Ipv6ForwardingRule rule = buildTestForwardingRule(ifIndex, neigh, mac);
|
||||||
coordinator.tetherOffloadRuleAdd(mIpServer, rule);
|
coordinator.tetherOffloadRuleAdd(mIpServer, rule);
|
||||||
verify(mNetd, never()).tetherOffloadRuleAdd(any());
|
verifyNeverTetherOffloadRuleAdd();
|
||||||
LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules =
|
LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules =
|
||||||
coordinator.getForwardingRulesForTesting().get(mIpServer);
|
coordinator.getForwardingRulesForTesting().get(mIpServer);
|
||||||
assertNull(rules);
|
assertNull(rules);
|
||||||
@@ -550,12 +646,29 @@ public class BpfCoordinatorTest {
|
|||||||
// The rule can't be updated.
|
// The rule can't be updated.
|
||||||
coordinator.tetherOffloadRuleUpdate(mIpServer, rule.upstreamIfindex + 1 /* new */);
|
coordinator.tetherOffloadRuleUpdate(mIpServer, rule.upstreamIfindex + 1 /* new */);
|
||||||
verify(mNetd, never()).tetherOffloadRuleRemove(any());
|
verify(mNetd, never()).tetherOffloadRuleRemove(any());
|
||||||
verify(mNetd, never()).tetherOffloadRuleAdd(any());
|
verifyNeverTetherOffloadRuleAdd();
|
||||||
rules = coordinator.getForwardingRulesForTesting().get(mIpServer);
|
rules = coordinator.getForwardingRulesForTesting().get(mIpServer);
|
||||||
assertNotNull(rules);
|
assertNotNull(rules);
|
||||||
assertEquals(1, rules.size());
|
assertEquals(1, rules.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBpfDisabledbyConfig() throws Exception {
|
||||||
|
setupFunctioningNetdInterface();
|
||||||
|
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(false);
|
||||||
|
|
||||||
|
checkBpfDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
|
public void testBpfDisabledbyNoBpfIngressMap() throws Exception {
|
||||||
|
setupFunctioningNetdInterface();
|
||||||
|
doReturn(null).when(mDeps).getBpfIngressMap();
|
||||||
|
|
||||||
|
checkBpfDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTetheringConfigSetPollingInterval() throws Exception {
|
public void testTetheringConfigSetPollingInterval() throws Exception {
|
||||||
setupFunctioningNetdInterface();
|
setupFunctioningNetdInterface();
|
||||||
|
|||||||
Reference in New Issue
Block a user