[Thread] avoid kernel-generated lla on thread-wpan

OpenThread generates the link-local address randomly, so the kernel
shound't generate another lla again.

Bug: 305605130

Change-Id: I0ec79adf0de4edc6921703c3cc50cfcfe63b853b
This commit is contained in:
Kangping Dong 2024-04-12 11:24:24 +08:00
commit 8658ef364d
5 changed files with 95 additions and 6 deletions

View file

@ -41,6 +41,10 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
public static final short IFLA_ADDRESS = 1;
public static final short IFLA_IFNAME = 3;
public static final short IFLA_MTU = 4;
public static final short IFLA_INET6_ADDR_GEN_MODE = 8;
public static final short IFLA_AF_SPEC = 26;
public static final short IN6_ADDR_GEN_MODE_NONE = 1;
private int mMtu;
@NonNull

View file

@ -49,7 +49,7 @@ public class StructIfinfoMsg extends Struct {
@Field(order = 4, type = Type.U32)
public final long change;
StructIfinfoMsg(short family, int type, int index, long flags, long change) {
public StructIfinfoMsg(short family, int type, int index, long flags, long change) {
this.family = family;
this.type = type;
this.index = index;

View file

@ -16,7 +16,18 @@
package com.android.server.thread;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.EADDRINUSE;
import static android.system.OsConstants.IFF_MULTICAST;
import static android.system.OsConstants.IFF_NOARP;
import static android.system.OsConstants.NETLINK_ROUTE;
import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_AF_SPEC;
import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_INET6_ADDR_GEN_MODE;
import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IN6_ADDR_GEN_MODE_NONE;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import android.annotation.Nullable;
import android.net.IpPrefix;
@ -29,8 +40,12 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import com.android.net.module.util.HexDump;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.net.module.util.netlink.NetlinkUtils;
import com.android.net.module.util.netlink.StructIfinfoMsg;
import com.android.net.module.util.netlink.StructNlAttr;
import com.android.net.module.util.netlink.StructNlMsgHdr;
import com.android.server.thread.openthread.Ipv6AddressInfo;
import com.android.server.thread.openthread.OnMeshPrefixConfig;
@ -42,12 +57,15 @@ import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
/** Controller for virtual/tunnel network interfaces. */
public class TunInterfaceController {
private static final String TAG = "TunIfController";
private static final boolean DBG = false;
private static final long INFINITE_LIFETIME = 0xffffffffL;
static final int MTU = 1280;
@ -89,6 +107,8 @@ public class TunInterfaceController {
} catch (SocketException e) {
throw new IOException("Failed to get NetworkInterface", e);
}
setAddrGenModeToNone();
}
public void destroyTunInterface() {
@ -339,4 +359,66 @@ public class TunInterfaceController {
Log.e(TAG, "failed to leave group " + address.getHostAddress(), e);
}
}
/**
* Sets the address generation mode to {@code IN6_ADDR_GEN_MODE_NONE}.
*
* <p>So that the "thread-wpan" interface has only one IPv6 link local address which is
* generated by OpenThread.
*/
private void setAddrGenModeToNone() {
StructNlMsgHdr header = new StructNlMsgHdr();
header.nlmsg_type = RTM_NEWLINK;
header.nlmsg_pid = 0;
header.nlmsg_seq = 0;
header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
StructIfinfoMsg ifInfo =
new StructIfinfoMsg(
(short) 0 /* family */,
0 /* type */,
Os.if_nametoindex(mIfName),
(IFF_MULTICAST | IFF_NOARP) /* flags */,
0xffffffff /* change */);
// Nested attributes
// IFLA_AF_SPEC
// AF_INET6
// IFLA_INET6_ADDR_GEN_MODE
StructNlAttr addrGenMode =
new StructNlAttr(IFLA_INET6_ADDR_GEN_MODE, (byte) IN6_ADDR_GEN_MODE_NONE);
StructNlAttr afInet6 = new StructNlAttr((short) AF_INET6, addrGenMode);
StructNlAttr afSpec = new StructNlAttr(IFLA_AF_SPEC, afInet6);
final int msgLength =
StructNlMsgHdr.STRUCT_SIZE
+ StructIfinfoMsg.STRUCT_SIZE
+ afSpec.getAlignedLength();
byte[] msg = new byte[msgLength];
ByteBuffer buf = ByteBuffer.wrap(msg);
buf.order(ByteOrder.nativeOrder());
header.nlmsg_len = msgLength;
header.pack(buf);
ifInfo.pack(buf);
afSpec.pack(buf);
if (buf.position() != msgLength) {
throw new AssertionError(
String.format(
"Unexpected netlink message size (actual = %d, expected = %d)",
buf.position(), msgLength));
}
if (DBG) {
Log.d(TAG, "ADDR_GEN_MODE message is:");
Log.d(TAG, HexDump.dumpHexString(msg));
}
try {
NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
} catch (ErrnoException e) {
Log.e(TAG, "Failed to set ADDR_GEN_MODE to NONE", e);
}
}
}

View file

@ -176,7 +176,7 @@ public class ThreadIntegrationTest {
// TODO (b/323300829): add test for removing an OT address
@Test
public void tunInterface_joinedNetwork_otAddressesAddedToTunInterface() throws Exception {
public void tunInterface_joinedNetwork_otAndTunAddressesMatch() throws Exception {
mController.joinAndWait(DEFAULT_DATASET);
List<Inet6Address> otAddresses = mOtCtl.getAddresses();
@ -185,9 +185,12 @@ public class ThreadIntegrationTest {
// that we can write assertThat() in the Predicate
waitFor(
() -> {
String ifconfig = runShellCommand("ifconfig thread-wpan");
return otAddresses.stream()
.allMatch(addr -> ifconfig.contains(addr.getHostAddress()));
List<Inet6Address> tunAddresses =
getIpv6LinkAddresses("thread-wpan").stream()
.map(linkAddr -> (Inet6Address) linkAddr.getAddress())
.toList();
return otAddresses.containsAll(tunAddresses)
&& tunAddresses.containsAll(otAddresses);
},
TUN_ADDR_UPDATE_TIMEOUT);
}

View file

@ -301,7 +301,7 @@ public final class IntegrationTestUtils {
return false;
}
public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) throws IOException {
public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) {
List<LinkAddress> addresses = new ArrayList<>();
final String cmd = " ip -6 addr show dev " + interfaceName;
final String output = runShellCommandOrThrow(cmd);