Merge "Add OT multicast addresses to tun interface." into main
This commit is contained in:
commit
aa72ee2dd5
3 changed files with 82 additions and 5 deletions
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package com.android.server.thread;
|
||||
|
||||
import static android.system.OsConstants.EADDRINUSE;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
|
|
@ -39,6 +41,10 @@ import java.io.IOException;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MulticastSocket;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -58,12 +64,16 @@ public class TunInterfaceController {
|
|||
private ParcelFileDescriptor mParcelTunFd;
|
||||
private FileDescriptor mNetlinkSocket;
|
||||
private static int sNetlinkSeqNo = 0;
|
||||
private final MulticastSocket mMulticastSocket; // For join group and leave group
|
||||
private NetworkInterface mNetworkInterface;
|
||||
private List<InetAddress> mMulticastAddresses = new ArrayList<>();
|
||||
|
||||
/** Creates a new {@link TunInterfaceController} instance for given interface. */
|
||||
public TunInterfaceController(String interfaceName) {
|
||||
mIfName = interfaceName;
|
||||
mLinkProperties.setInterfaceName(mIfName);
|
||||
mLinkProperties.setMtu(MTU);
|
||||
mMulticastSocket = createMulticastSocket();
|
||||
}
|
||||
|
||||
/** Returns link properties of the Thread TUN interface. */
|
||||
|
|
@ -83,6 +93,11 @@ public class TunInterfaceController {
|
|||
} catch (ErrnoException e) {
|
||||
throw new IOException("Failed to create netlink socket", e);
|
||||
}
|
||||
try {
|
||||
mNetworkInterface = NetworkInterface.getByName(mIfName);
|
||||
} catch (SocketException e) {
|
||||
throw new IOException("Failed to get NetworkInterface", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroyTunInterface() {
|
||||
|
|
@ -94,6 +109,7 @@ public class TunInterfaceController {
|
|||
}
|
||||
mParcelTunFd = null;
|
||||
mNetlinkSocket = null;
|
||||
mNetworkInterface = null;
|
||||
}
|
||||
|
||||
/** Returns the FD of the tunnel interface. */
|
||||
|
|
@ -187,6 +203,7 @@ public class TunInterfaceController {
|
|||
|
||||
public void updateAddresses(List<Ipv6AddressInfo> addressInfoList) {
|
||||
final List<LinkAddress> newLinkAddresses = new ArrayList<>();
|
||||
final List<InetAddress> newMulticastAddresses = new ArrayList<>();
|
||||
boolean hasActiveOmrAddress = false;
|
||||
|
||||
for (Ipv6AddressInfo addressInfo : addressInfoList) {
|
||||
|
|
@ -199,12 +216,10 @@ public class TunInterfaceController {
|
|||
for (Ipv6AddressInfo addressInfo : addressInfoList) {
|
||||
InetAddress address = addressInfoToInetAddress(addressInfo);
|
||||
if (address.isMulticastAddress()) {
|
||||
// TODO: Logging here will create repeated logs for a single multicast address, and
|
||||
// it currently is not mandatory for debugging. Add log for ignored multicast
|
||||
// address when necessary.
|
||||
continue;
|
||||
newMulticastAddresses.add(address);
|
||||
} else {
|
||||
newLinkAddresses.add(newLinkAddress(addressInfo, hasActiveOmrAddress));
|
||||
}
|
||||
newLinkAddresses.add(newLinkAddress(addressInfo, hasActiveOmrAddress));
|
||||
}
|
||||
|
||||
final CompareResult<LinkAddress> addressDiff =
|
||||
|
|
@ -215,6 +230,17 @@ public class TunInterfaceController {
|
|||
for (LinkAddress linkAddress : addressDiff.added) {
|
||||
addAddress(linkAddress);
|
||||
}
|
||||
|
||||
final CompareResult<InetAddress> multicastAddressDiff =
|
||||
new CompareResult<>(mMulticastAddresses, newMulticastAddresses);
|
||||
for (InetAddress address : multicastAddressDiff.removed) {
|
||||
leaveGroup(address);
|
||||
}
|
||||
for (InetAddress address : multicastAddressDiff.added) {
|
||||
joinGroup(address);
|
||||
}
|
||||
mMulticastAddresses.clear();
|
||||
mMulticastAddresses.addAll(newMulticastAddresses);
|
||||
}
|
||||
|
||||
private RouteInfo getRouteForAddress(LinkAddress linkAddress) {
|
||||
|
|
@ -274,4 +300,37 @@ public class TunInterfaceController {
|
|||
deprecationTimeMillis,
|
||||
LinkAddress.LIFETIME_PERMANENT /* expirationTime */);
|
||||
}
|
||||
|
||||
private MulticastSocket createMulticastSocket() {
|
||||
try {
|
||||
return new MulticastSocket();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to create multicast socket ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void joinGroup(InetAddress address) {
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(address, 0);
|
||||
try {
|
||||
mMulticastSocket.joinGroup(socketAddress, mNetworkInterface);
|
||||
} catch (IOException e) {
|
||||
if (e.getCause() instanceof ErrnoException) {
|
||||
ErrnoException ee = (ErrnoException) e.getCause();
|
||||
if (ee.errno == EADDRINUSE) {
|
||||
Log.w(TAG, "Already joined group" + address.getHostAddress(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "failed to join group " + address.getHostAddress(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void leaveGroup(InetAddress address) {
|
||||
InetSocketAddress socketAddress = new InetSocketAddress(address, 0);
|
||||
try {
|
||||
mMulticastSocket.leaveGroup(socketAddress, mNetworkInterface);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "failed to leave group " + address.getHostAddress(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ java_defaults {
|
|||
"testables",
|
||||
"ThreadNetworkTestUtils",
|
||||
"truth",
|
||||
"ot-daemon-aidl-java",
|
||||
],
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
|
|
|
|||
|
|
@ -22,15 +22,18 @@ 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.isInMulticastGroup;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
|
||||
import static com.android.server.thread.openthread.IOtDaemon.TUN_IF_NAME;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.thread.utils.FullThreadDevice;
|
||||
|
|
@ -83,6 +86,9 @@ public class ThreadIntegrationTest {
|
|||
private static final ActiveOperationalDataset DEFAULT_DATASET =
|
||||
ActiveOperationalDataset.fromThreadTlvs(DEFAULT_DATASET_TLVS);
|
||||
|
||||
private static final Inet6Address GROUP_ADDR_ALL_ROUTERS =
|
||||
(Inet6Address) InetAddresses.parseNumericAddress("ff02::2");
|
||||
|
||||
@Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
|
||||
|
||||
private ExecutorService mExecutor;
|
||||
|
|
@ -224,6 +230,13 @@ public class ThreadIntegrationTest {
|
|||
mOtCtl.executeCommand("br enable");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinNetwork_tunInterfaceJoinsAllRouterMulticastGroup() throws Exception {
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
|
||||
assertTunInterfaceMemberOfGroup(GROUP_ADDR_ALL_ROUTERS);
|
||||
}
|
||||
|
||||
// TODO (b/323300829): add more tests for integration with linux platform and
|
||||
// ConnectivityService
|
||||
|
||||
|
|
@ -259,4 +272,8 @@ public class ThreadIntegrationTest {
|
|||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTunInterfaceMemberOfGroup(Inet6Address address) throws Exception {
|
||||
waitFor(() -> isInMulticastGroup(TUN_IF_NAME, address), TUN_ADDR_UPDATE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue