[CLATJ#10] ClatCoordinator: detect mtu
Detect the available mtu for clat. The native mtu detect function
is moved from netd to libclat which is called by jni. The java
adjust mtu function is moved from netd native code.
Bug: 212345928
Test: flash and boot
Run "atest ClatCoordinatorTest" in a followup commit.
Change-Id: Icf5f57c7e7b947997b76152722e46acdd9d95c1a
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index d3895b3..eefb94b 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -124,6 +124,27 @@
return fd;
}
+static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jobject clazz,
+ jstring platSubnet,
+ jint plat_suffix, jint mark) {
+ ScopedUtfChars platSubnetStr(env, platSubnet);
+
+ in6_addr plat_subnet;
+ if (inet_pton(AF_INET6, platSubnetStr.c_str(), &plat_subnet) != 1) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "Invalid plat prefix address %s",
+ platSubnetStr.c_str());
+ return -1;
+ }
+
+ int ret = net::clat::detect_mtu(&plat_subnet, plat_suffix, mark);
+ if (ret < 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "detect mtu failed: %s", strerror(-ret));
+ return -1;
+ }
+
+ return ret;
+}
+
/*
* JNI registration.
*/
@@ -136,6 +157,8 @@
(void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
{"createTunInterface", "(Ljava/lang/String;)I",
(void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
+ {"detectMtu", "(Ljava/lang/String;II)I",
+ (void*)com_android_server_connectivity_ClatCoordinator_detectMtu},
};
int register_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 22edf1b..1702930 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.INetd.PERMISSION_SYSTEM;
+
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.INetd;
@@ -28,6 +32,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
/**
* This coordinator is responsible for providing clat relevant functionality.
@@ -37,6 +43,13 @@
public class ClatCoordinator {
private static final String TAG = ClatCoordinator.class.getSimpleName();
+ // Sync from external/android-clat/clatd.c
+ // 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header.
+ @VisibleForTesting
+ static final int MTU_DELTA = 28;
+ @VisibleForTesting
+ static final int CLAT_MAX_MTU = 65536;
+
// This must match the interface prefix in clatd.c.
private static final String CLAT_PREFIX = "v4-";
@@ -46,6 +59,7 @@
static final String INIT_V4ADDR_STRING = "192.0.0.4";
@VisibleForTesting
static final int INIT_V4ADDR_PREFIX_LEN = 29;
+ private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8");
private static final int INVALID_PID = 0;
@@ -97,6 +111,35 @@
@NonNull String prefix64) throws IOException {
return generateIpv6Address(iface, v4, prefix64);
}
+
+ /**
+ * Detect MTU.
+ */
+ public int jniDetectMtu(@NonNull String platSubnet, int platSuffix, int mark)
+ throws IOException {
+ return detectMtu(platSubnet, platSuffix, mark);
+ }
+ }
+
+ @VisibleForTesting
+ static int getFwmark(int netId) {
+ // See union Fwmark in system/netd/include/Fwmark.h
+ return (netId & 0xffff)
+ | 0x1 << 16 // protectedFromVpn: true
+ | 0x1 << 17 // explicitlySelected: true
+ | (PERMISSION_SYSTEM & 0x3) << 18;
+ }
+
+ @VisibleForTesting
+ static int adjustMtu(int mtu) {
+ // clamp to minimum ipv6 mtu - this probably cannot ever trigger
+ if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU;
+ // clamp to buffer size
+ if (mtu > CLAT_MAX_MTU) mtu = CLAT_MAX_MTU;
+ // decrease by ipv6(40) + ipv6 fragmentation header(8) vs ipv4(20) overhead of 28 bytes
+ mtu -= MTU_DELTA;
+
+ return mtu;
}
public ClatCoordinator(@NonNull Dependencies deps) {
@@ -148,6 +191,13 @@
Log.e(TAG, "Disable IPv6 on " + tunIface + " failed: " + e);
}
+ // Detect ipv4 mtu.
+ final Integer fwmark = getFwmark(netId);
+ final int detectedMtu = mDeps.jniDetectMtu(pfx96,
+ ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
+ final int mtu = adjustMtu(detectedMtu);
+ Log.i(TAG, "ipv4 mtu is " + mtu);
+
// TODO: start clatd and returns local xlat464 v6 address.
return null;
}
@@ -157,4 +207,6 @@
private static native String generateIpv6Address(String iface, String v4, String prefix64)
throws IOException;
private static native int createTunInterface(String tuniface) throws IOException;
+ private static native int detectMtu(String platSubnet, int platSuffix, int mark)
+ throws IOException;
}