[CLATJ#9] ClatCoordinator: open tun interface
Open the v4-... tun interface for clat. The native function
is moved from netd to jni.
Bug: 212345928
Test: flash and boot
Run "atest ClatCoordinatorTest" in a followup commit.
Change-Id: I3f3c587275125ce3fc7481006947211f17dbb2d4
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index e3e5000..d3895b3 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -15,7 +15,11 @@
*/
#include <arpa/inet.h>
+#include <fcntl.h>
+#include <linux/if_tun.h>
+#include <linux/ioctl.h>
#include <nativehelper/JNIHelp.h>
+#include <net/if.h>
#include <netjniutils/netjniutils.h>
@@ -92,6 +96,34 @@
return env->NewStringUTF(addrstr);
}
+static jint com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv* env,
+ jobject clazz,
+ jstring tuniface) {
+ ScopedUtfChars v4interface(env, tuniface);
+
+ // open the tun device in non blocking mode as required by clatd
+ jint fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd == -1) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "open tun device failed (%s)",
+ strerror(errno));
+ return -1;
+ }
+
+ struct ifreq ifr = {
+ .ifr_flags = IFF_TUN,
+ };
+ strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, TUNSETIFF, &ifr, sizeof(ifr))) {
+ close(fd);
+ jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(TUNSETIFF) failed (%s)",
+ strerror(errno));
+ return -1;
+ }
+
+ return fd;
+}
+
/*
* JNI registration.
*/
@@ -102,6 +134,8 @@
{"generateIpv6Address",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
+ {"createTunInterface", "(Ljava/lang/String;)I",
+ (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
};
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 11deb78..22edf1b 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -20,6 +20,10 @@
import android.annotation.Nullable;
import android.net.INetd;
import android.net.IpPrefix;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -33,6 +37,9 @@
public class ClatCoordinator {
private static final String TAG = ClatCoordinator.class.getSimpleName();
+ // This must match the interface prefix in clatd.c.
+ private static final String CLAT_PREFIX = "v4-";
+
// For historical reasons, start with 192.0.0.4, and after that, use all subsequent addresses
// in 192.0.0.0/29 (RFC 7335).
@VisibleForTesting
@@ -59,6 +66,21 @@
public abstract INetd getNetd();
/**
+ * @see ParcelFileDescriptor#adoptFd(int).
+ */
+ @NonNull
+ public ParcelFileDescriptor adoptFd(int fd) {
+ return ParcelFileDescriptor.adoptFd(fd);
+ }
+
+ /**
+ * Create tun interface for a given interface name.
+ */
+ public int jniCreateTunInterface(@NonNull String tuniface) throws IOException {
+ return createTunInterface(tuniface);
+ }
+
+ /**
* Pick an IPv4 address for clat.
*/
@NonNull
@@ -109,6 +131,23 @@
throw new IOException("no IPv6 addresses were available for clat: " + e);
}
+ // [3] Open, configure and bring up the tun interface.
+ // Create the v4-... tun interface.
+ final String tunIface = CLAT_PREFIX + iface;
+ final ParcelFileDescriptor tunFd;
+ try {
+ tunFd = mDeps.adoptFd(mDeps.jniCreateTunInterface(tunIface));
+ } catch (IOException e) {
+ throw new IOException("Create tun interface " + tunIface + " failed: " + e);
+ }
+
+ // disable IPv6 on it - failing to do so is not a critical error
+ try {
+ mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.e(TAG, "Disable IPv6 on " + tunIface + " failed: " + e);
+ }
+
// TODO: start clatd and returns local xlat464 v6 address.
return null;
}
@@ -117,4 +156,5 @@
throws IOException;
private static native String generateIpv6Address(String iface, String v4, String prefix64)
throws IOException;
+ private static native int createTunInterface(String tuniface) throws IOException;
}