From 8658ef364d0c5fc2ca4a8d17cc10bffe6ec7adc8 Mon Sep 17 00:00:00 2001 From: Kangping Dong Date: Fri, 12 Apr 2024 11:24:24 +0800 Subject: [PATCH] [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 --- .../util/netlink/RtNetlinkLinkMessage.java | 4 + .../module/util/netlink/StructIfinfoMsg.java | 2 +- .../server/thread/TunInterfaceController.java | 82 +++++++++++++++++++ .../net/thread/ThreadIntegrationTest.java | 11 ++- .../thread/utils/IntegrationTestUtils.java | 2 +- 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java index 92ec0c4e4c..df7010e792 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java @@ -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 diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java index 02d1574bff..28eeaea873 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java @@ -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; diff --git a/thread/service/java/com/android/server/thread/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java index eba8f3b4cb..c57a79d945 100644 --- a/thread/service/java/com/android/server/thread/TunInterfaceController.java +++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java @@ -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}. + * + *

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); + } + } } diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java index 4028014e38..d7ae5e4ad5 100644 --- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java +++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java @@ -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 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 tunAddresses = + getIpv6LinkAddresses("thread-wpan").stream() + .map(linkAddr -> (Inet6Address) linkAddr.getAddress()) + .toList(); + return otAddresses.containsAll(tunAddresses) + && tunAddresses.containsAll(otAddresses); }, TUN_ADDR_UPDATE_TIMEOUT); } diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java index 78f57707bd..ada46c8536 100644 --- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java +++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java @@ -301,7 +301,7 @@ public final class IntegrationTestUtils { return false; } - public static List getIpv6LinkAddresses(String interfaceName) throws IOException { + public static List getIpv6LinkAddresses(String interfaceName) { List addresses = new ArrayList<>(); final String cmd = " ip -6 addr show dev " + interfaceName; final String output = runShellCommandOrThrow(cmd);