Merge "Add netdata prefixes to tun interface routing table." into main
This commit is contained in:
commit
43b62ae5ff
4 changed files with 146 additions and 7 deletions
|
|
@ -122,6 +122,7 @@ import com.android.server.thread.openthread.IOtDaemonCallback;
|
|||
import com.android.server.thread.openthread.IOtStatusReceiver;
|
||||
import com.android.server.thread.openthread.Ipv6AddressInfo;
|
||||
import com.android.server.thread.openthread.MeshcopTxtAttributes;
|
||||
import com.android.server.thread.openthread.OnMeshPrefixConfig;
|
||||
import com.android.server.thread.openthread.OtDaemonState;
|
||||
|
||||
import libcore.util.HexEncoding;
|
||||
|
|
@ -1234,6 +1235,18 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
|
|||
}
|
||||
}
|
||||
|
||||
private void handlePrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
|
||||
checkOnHandlerThread();
|
||||
|
||||
mTunIfController.updatePrefixes(onMeshPrefixConfigList);
|
||||
|
||||
// The OT daemon can send link property updates before the networkAgent is
|
||||
// registered
|
||||
if (mNetworkAgent != null) {
|
||||
mNetworkAgent.sendLinkProperties(mTunIfController.getLinkProperties());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendLocalNetworkConfig() {
|
||||
if (mNetworkAgent == null) {
|
||||
return;
|
||||
|
|
@ -1581,5 +1594,10 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
|
|||
public void onBackboneRouterStateChanged(BackboneRouterState state) {
|
||||
mHandler.post(() -> handleMulticastForwardingChanged(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
|
||||
mHandler.post(() -> handlePrefixChanged(onMeshPrefixConfigList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
|
|||
import com.android.net.module.util.netlink.NetlinkUtils;
|
||||
import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
|
||||
import com.android.server.thread.openthread.Ipv6AddressInfo;
|
||||
import com.android.server.thread.openthread.OnMeshPrefixConfig;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
|
@ -66,7 +67,8 @@ public class TunInterfaceController {
|
|||
private static int sNetlinkSeqNo = 0;
|
||||
private final MulticastSocket mMulticastSocket; // For join group and leave group
|
||||
private NetworkInterface mNetworkInterface;
|
||||
private List<InetAddress> mMulticastAddresses = new ArrayList<>();
|
||||
private final List<InetAddress> mMulticastAddresses = new ArrayList<>();
|
||||
private final List<RouteInfo> mNetDataPrefixes = new ArrayList<>();
|
||||
|
||||
/** Creates a new {@link TunInterfaceController} instance for given interface. */
|
||||
public TunInterfaceController(String interfaceName) {
|
||||
|
|
@ -243,13 +245,40 @@ public class TunInterfaceController {
|
|||
mMulticastAddresses.addAll(newMulticastAddresses);
|
||||
}
|
||||
|
||||
public void updatePrefixes(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
|
||||
final List<RouteInfo> newNetDataPrefixes = new ArrayList<>();
|
||||
|
||||
for (OnMeshPrefixConfig onMeshPrefixConfig : onMeshPrefixConfigList) {
|
||||
newNetDataPrefixes.add(getRouteForOnMeshPrefix(onMeshPrefixConfig));
|
||||
}
|
||||
|
||||
final CompareResult<RouteInfo> prefixDiff =
|
||||
new CompareResult<>(mNetDataPrefixes, newNetDataPrefixes);
|
||||
for (RouteInfo routeRemoved : prefixDiff.removed) {
|
||||
mLinkProperties.removeRoute(routeRemoved);
|
||||
}
|
||||
for (RouteInfo routeAdded : prefixDiff.added) {
|
||||
mLinkProperties.addRoute(routeAdded);
|
||||
}
|
||||
|
||||
mNetDataPrefixes.clear();
|
||||
mNetDataPrefixes.addAll(newNetDataPrefixes);
|
||||
}
|
||||
|
||||
private RouteInfo getRouteForAddress(LinkAddress linkAddress) {
|
||||
return new RouteInfo(
|
||||
new IpPrefix(linkAddress.getAddress(), linkAddress.getPrefixLength()),
|
||||
null,
|
||||
mIfName,
|
||||
RouteInfo.RTN_UNICAST,
|
||||
MTU);
|
||||
return getRouteForIpPrefix(
|
||||
new IpPrefix(linkAddress.getAddress(), linkAddress.getPrefixLength()));
|
||||
}
|
||||
|
||||
private RouteInfo getRouteForOnMeshPrefix(OnMeshPrefixConfig onMeshPrefixConfig) {
|
||||
return getRouteForIpPrefix(
|
||||
new IpPrefix(
|
||||
bytesToInet6Address(onMeshPrefixConfig.prefix),
|
||||
onMeshPrefixConfig.prefixLength));
|
||||
}
|
||||
|
||||
private RouteInfo getRouteForIpPrefix(IpPrefix ipPrefix) {
|
||||
return new RouteInfo(ipPrefix, null, mIfName, RouteInfo.RTN_UNICAST, MTU);
|
||||
}
|
||||
|
||||
/** Called by {@link ThreadNetworkControllerService} to do clean up when ot-daemon is dead. */
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ 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.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;
|
||||
|
||||
|
|
@ -34,9 +36,11 @@ import static com.google.common.truth.Truth.assertThat;
|
|||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
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.thread.utils.FullThreadDevice;
|
||||
import android.net.thread.utils.OtDaemonController;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule;
|
||||
|
|
@ -76,6 +80,9 @@ public class ThreadIntegrationTest {
|
|||
// The maximum time for OT addresses to be propagated to the TUN interface "thread-wpan"
|
||||
private static final Duration TUN_ADDR_UPDATE_TIMEOUT = Duration.ofSeconds(1);
|
||||
|
||||
// The maximum time for changes to be propagated to netdata.
|
||||
private static final Duration NET_DATA_UPDATE_TIMEOUT = Duration.ofSeconds(1);
|
||||
|
||||
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
|
||||
private static final byte[] DEFAULT_DATASET_TLVS =
|
||||
base16().decode(
|
||||
|
|
@ -90,6 +97,10 @@ public class ThreadIntegrationTest {
|
|||
private static final Inet6Address GROUP_ADDR_ALL_ROUTERS =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("ff02::2");
|
||||
|
||||
private static final String TEST_NO_SLAAC_PREFIX = "9101:dead:beef:cafe::/64";
|
||||
private static final InetAddress TEST_NO_SLAAC_PREFIX_ADDRESS =
|
||||
InetAddresses.parseNumericAddress("9101:dead:beef:cafe::");
|
||||
|
||||
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
|
||||
|
||||
private ExecutorService mExecutor;
|
||||
|
|
@ -253,6 +264,49 @@ public class ThreadIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPrefixToNetData_routeIsAddedToTunInterface() throws Exception {
|
||||
ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
|
||||
// Ftd child doesn't have the ability to add a prefix, so let BR itself add a prefix.
|
||||
mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
|
||||
mOtCtl.executeCommand("netdata register");
|
||||
waitFor(
|
||||
() -> {
|
||||
String netData = mOtCtl.executeCommand("netdata show");
|
||||
return getPrefixesFromNetData(netData).contains(TEST_NO_SLAAC_PREFIX);
|
||||
},
|
||||
NET_DATA_UPDATE_TIMEOUT);
|
||||
|
||||
LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
|
||||
assertThat(lp).isNotNull();
|
||||
assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removePrefixFromNetData_routeIsRemovedFromTunInterface() throws Exception {
|
||||
ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
|
||||
mOtCtl.executeCommand("netdata register");
|
||||
|
||||
mOtCtl.executeCommand("prefix remove " + TEST_NO_SLAAC_PREFIX);
|
||||
mOtCtl.executeCommand("netdata register");
|
||||
waitFor(
|
||||
() -> {
|
||||
String netData = mOtCtl.executeCommand("netdata show");
|
||||
return !getPrefixesFromNetData(netData).contains(TEST_NO_SLAAC_PREFIX);
|
||||
},
|
||||
NET_DATA_UPDATE_TIMEOUT);
|
||||
|
||||
LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
|
||||
assertThat(lp).isNotNull();
|
||||
assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
// TODO (b/323300829): add more tests for integration with linux platform and
|
||||
// ConnectivityService
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package android.net.thread.utils;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
|
||||
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
|
||||
|
|
@ -24,17 +25,24 @@ import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_AD
|
|||
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TestNetworkInterface;
|
||||
import android.net.nsd.NsdManager;
|
||||
import android.net.nsd.NsdServiceInfo;
|
||||
import android.net.thread.ThreadNetworkController;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.structs.Icmpv6Header;
|
||||
|
|
@ -375,6 +383,36 @@ public final class IntegrationTestUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String getPrefixesFromNetData(String netData) {
|
||||
int startIdx = netData.indexOf("Prefixes:");
|
||||
int endIdx = netData.indexOf("Routes:");
|
||||
return netData.substring(startIdx, endIdx);
|
||||
}
|
||||
|
||||
public static Network getThreadNetwork(Duration timeout) throws Exception {
|
||||
CompletableFuture<Network> networkFuture = new CompletableFuture<>();
|
||||
ConnectivityManager cm =
|
||||
ApplicationProvider.getApplicationContext()
|
||||
.getSystemService(ConnectivityManager.class);
|
||||
NetworkRequest.Builder networkRequestBuilder =
|
||||
new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_THREAD);
|
||||
// Before V, we need to explicitly set `NET_CAPABILITY_LOCAL_NETWORK` capability to request
|
||||
// a Thread network.
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
networkRequestBuilder.addCapability(NET_CAPABILITY_LOCAL_NETWORK);
|
||||
}
|
||||
NetworkRequest networkRequest = networkRequestBuilder.build();
|
||||
ConnectivityManager.NetworkCallback networkCallback =
|
||||
new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
networkFuture.complete(network);
|
||||
}
|
||||
};
|
||||
cm.registerNetworkCallback(networkRequest, networkCallback);
|
||||
return networkFuture.get(timeout.toSeconds(), SECONDS);
|
||||
}
|
||||
|
||||
private static class DefaultDiscoveryListener implements NsdManager.DiscoveryListener {
|
||||
@Override
|
||||
public void onStartDiscoveryFailed(String serviceType, int errorCode) {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue