[Thread] prefer only ML-EID in case OMR is missing
This is to avoid applications uses Aloc address for source address which would cause issues when there are multiple devices sharing the same Aloc. Bug: 396019291 Change-Id: I287007ddecd9d0fa2ac8da92f4de691e7844b259
This commit is contained in:
parent
ca91ebdcab
commit
74a6ca6478
5 changed files with 102 additions and 21 deletions
|
|
@ -326,12 +326,13 @@ public class TunInterfaceController {
|
|||
private static LinkAddress newLinkAddress(
|
||||
Ipv6AddressInfo addressInfo, boolean hasActiveOmrAddress) {
|
||||
// Mesh-local addresses and OMR address have the same scope, to distinguish them we set
|
||||
// mesh-local addresses as deprecated when there is an active OMR address.
|
||||
// mesh-local addresses as deprecated when there is an active OMR address. If OMR address
|
||||
// is missing, only ML-EID in mesh-local addresses will be set preferred.
|
||||
// For OMR address and link-local address we only use the value isPreferred set by
|
||||
// ot-daemon.
|
||||
boolean isPreferred = addressInfo.isPreferred;
|
||||
if (addressInfo.isMeshLocal && hasActiveOmrAddress) {
|
||||
isPreferred = false;
|
||||
if (addressInfo.isMeshLocal) {
|
||||
isPreferred = (!hasActiveOmrAddress && addressInfo.isMeshLocalEid);
|
||||
}
|
||||
|
||||
final long deprecationTimeMillis =
|
||||
|
|
|
|||
|
|
@ -19,12 +19,10 @@ package android.net.thread.cts;
|
|||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.thread.ThreadNetworkController;
|
||||
import android.net.thread.ThreadNetworkManager;
|
||||
import android.os.Build;
|
||||
|
||||
|
|
@ -41,8 +39,6 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Tests for {@link ThreadNetworkManager}. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_LEADER;
|
|||
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_STOPPED;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.CALLBACK_TIMEOUT;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getIpv6Addresses;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getPrefixesFromNetData;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getThreadNetwork;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
|
||||
import static android.net.thread.utils.ThreadNetworkControllerWrapper.JOIN_TIMEOUT;
|
||||
import static android.os.SystemClock.elapsedRealtime;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
|
||||
|
|
@ -38,6 +40,7 @@ import static com.google.common.io.BaseEncoding.base16;
|
|||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
|
@ -46,23 +49,26 @@ import android.content.Context;
|
|||
import android.net.ConnectivityManager;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.thread.utils.FullThreadDevice;
|
||||
import android.net.thread.utils.OtDaemonController;
|
||||
import android.net.thread.utils.TapTestNetworkTracker;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresSimulationThreadDevice;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
|
||||
import android.net.thread.utils.ThreadNetworkControllerWrapper;
|
||||
import android.net.thread.utils.ThreadStateListener;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.filters.LargeTest;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
|
@ -102,6 +108,12 @@ public class ThreadIntegrationTest {
|
|||
|
||||
private static final Duration NETWORK_CALLBACK_TIMEOUT = Duration.ofSeconds(10);
|
||||
|
||||
// The duration between attached and OMR address shows up on thread-wpan
|
||||
private static final Duration OMR_LINK_ADDR_TIMEOUT = Duration.ofSeconds(30);
|
||||
|
||||
// The duration between attached and addresses show up on thread-wpan
|
||||
private static final Duration LINK_ADDR_TIMEOUT = Duration.ofSeconds(2);
|
||||
|
||||
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
|
||||
private static final byte[] DEFAULT_DATASET_TLVS =
|
||||
base16().decode(
|
||||
|
|
@ -128,6 +140,8 @@ public class ThreadIntegrationTest {
|
|||
ThreadNetworkControllerWrapper.newInstance(mContext);
|
||||
private OtDaemonController mOtCtl;
|
||||
private FullThreadDevice mFtd;
|
||||
private HandlerThread mHandlerThread;
|
||||
private TapTestNetworkTracker mTestNetworkTracker;
|
||||
|
||||
public final boolean mIsBorderRouterEnabled;
|
||||
private final ThreadConfiguration mConfig;
|
||||
|
|
@ -152,6 +166,14 @@ public class ThreadIntegrationTest {
|
|||
mController.setEnabledAndWait(true);
|
||||
mController.setConfigurationAndWait(mConfig);
|
||||
mController.leaveAndWait();
|
||||
|
||||
mHandlerThread = new HandlerThread("ThreadIntegrationTest");
|
||||
mHandlerThread.start();
|
||||
|
||||
mTestNetworkTracker = new TapTestNetworkTracker(mContext, mHandlerThread.getLooper());
|
||||
assertThat(mTestNetworkTracker).isNotNull();
|
||||
mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
|
||||
|
||||
mFtd = new FullThreadDevice(10 /* nodeId */);
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +181,13 @@ public class ThreadIntegrationTest {
|
|||
public void tearDown() throws Exception {
|
||||
ThreadStateListener.stopAllListeners();
|
||||
|
||||
if (mTestNetworkTracker != null) {
|
||||
mTestNetworkTracker.tearDown();
|
||||
}
|
||||
if (mHandlerThread != null) {
|
||||
mHandlerThread.quitSafely();
|
||||
mHandlerThread.join();
|
||||
}
|
||||
mController.setTestNetworkAsUpstreamAndWait(null);
|
||||
mController.leaveAndWait();
|
||||
|
||||
|
|
@ -265,23 +294,51 @@ public class ThreadIntegrationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void joinNetworkWithBrDisabled_meshLocalAddressesArePreferred() throws Exception {
|
||||
// When BR feature is disabled, there is no OMR address, so the mesh-local addresses are
|
||||
// expected to be preferred.
|
||||
mOtCtl.executeCommand("br disable");
|
||||
public void joinNetwork_borderRouterEnabled_allMlAddrAreNotPreferredAndOmrIsPreferred()
|
||||
throws Exception {
|
||||
assumeTrue(mConfig.isBorderRouterEnabled());
|
||||
|
||||
mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
waitFor(
|
||||
() -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getOmrAddress()),
|
||||
OMR_LINK_ADDR_TIMEOUT);
|
||||
|
||||
IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
|
||||
List<LinkAddress> linkAddresses = getIpv6LinkAddresses("thread-wpan");
|
||||
for (LinkAddress address : linkAddresses) {
|
||||
if (meshLocalPrefix.contains(address.getAddress())) {
|
||||
assertThat(address.getDeprecationTime())
|
||||
.isGreaterThan(SystemClock.elapsedRealtime());
|
||||
assertThat(address.isPreferred()).isTrue();
|
||||
}
|
||||
}
|
||||
var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
|
||||
var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
|
||||
assertThat(meshLocalAddrs).isNotEmpty();
|
||||
assertThat(meshLocalAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
|
||||
assertThat(meshLocalAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
|
||||
.isTrue();
|
||||
var omrAddrs = linkAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getOmrAddress()));
|
||||
assertThat(omrAddrs).hasSize(1);
|
||||
assertThat(omrAddrs.get(0).isPreferred()).isTrue();
|
||||
assertThat(omrAddrs.get(0).getDeprecationTime() > elapsedRealtime()).isTrue();
|
||||
}
|
||||
|
||||
mOtCtl.executeCommand("br enable");
|
||||
@Test
|
||||
public void joinNetwork_borderRouterDisabled_onlyMlEidIsPreferred() throws Exception {
|
||||
assumeFalse(mConfig.isBorderRouterEnabled());
|
||||
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
waitFor(
|
||||
() -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getMlEid()),
|
||||
LINK_ADDR_TIMEOUT);
|
||||
|
||||
IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
|
||||
var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
|
||||
var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
|
||||
var mlEidAddrs = meshLocalAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getMlEid()));
|
||||
var nonMlEidAddrs = meshLocalAddrs.filter(addr -> !mlEidAddrs.contains(addr));
|
||||
assertThat(mlEidAddrs).hasSize(1);
|
||||
assertThat(mlEidAddrs.allMatch(addr -> addr.isPreferred())).isTrue();
|
||||
assertThat(mlEidAddrs.allMatch(addr -> addr.getDeprecationTime() > elapsedRealtime()))
|
||||
.isTrue();
|
||||
assertThat(nonMlEidAddrs).isNotEmpty();
|
||||
assertThat(nonMlEidAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
|
||||
assertThat(nonMlEidAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -479,6 +479,12 @@ object IntegrationTestUtils {
|
|||
return addresses
|
||||
}
|
||||
|
||||
/** Returns the list of [InetAddress] of the given network. */
|
||||
@JvmStatic
|
||||
fun getIpv6Addresses(interfaceName: String): List<InetAddress> {
|
||||
return getIpv6LinkAddresses(interfaceName).map { it.address }
|
||||
}
|
||||
|
||||
/** Return the first discovered service of `serviceType`. */
|
||||
@JvmStatic
|
||||
@Throws(Exception::class)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@ import android.os.SystemClock;
|
|||
import com.android.compatibility.common.util.SystemUtil;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Wrapper of the "/system/bin/ot-ctl" which can be used to send CLI commands to ot-daemon to
|
||||
|
|
@ -72,6 +74,25 @@ public final class OtDaemonController {
|
|||
.toList();
|
||||
}
|
||||
|
||||
/** Returns the OMR address of this device or {@code null} if it doesn't exist. */
|
||||
@Nullable
|
||||
public Inet6Address getOmrAddress() {
|
||||
List<Inet6Address> allAddresses = new ArrayList<>(getAddresses());
|
||||
allAddresses.removeAll(getMeshLocalAddresses());
|
||||
|
||||
List<Inet6Address> omrAddresses =
|
||||
allAddresses.stream()
|
||||
.filter(addr -> !addr.isLinkLocalAddress())
|
||||
.collect(Collectors.toList());
|
||||
if (omrAddresses.isEmpty()) {
|
||||
return null;
|
||||
} else if (omrAddresses.size() > 1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return omrAddresses.getFirst();
|
||||
}
|
||||
|
||||
/** Returns {@code true} if the Thread interface is up. */
|
||||
public boolean isInterfaceUp() {
|
||||
String output = executeCommand("ifconfig");
|
||||
|
|
|
|||
Loading…
Reference in a new issue