Test: separate BPF tethering offload tests to MTS

Needed because CTS release interval is longer than mainline module
release. Newer mainline module release may change low level BPF
offload related code (struct, path, ..). The existing CTS will be
broken. This situation blocks that we want to change low level BPF
offload code after Android CTS has been public released.

The test targets have been changed as follows.
1. CTS/TetheringTests verifies high level tethering functions.
   No matter what data path is.
2. MTS verifies low level tethering functions. It can always test the
   latest BPF codes.

Change list:
1. Add class MtsEthernetTetheringTest for MTS.

Before:
  [base class]                      [derived class]

  EthernetTetheringTestBase +--+--+ EthernetTetheringTest

After:
  [base class]                      [derived class]

                               +--+ EthernetTetheringTest
  EthernetTetheringTestBase +--+
                               +--+ MtsEthernetTetheringTest (new)

2. Separate BPF tethering offload tests to MTS.
Before:
  - TetheringTests (19 tests)
  EthernetTetheringTest#testIcmpv4Echo
  EthernetTetheringTest#testIcmpv6Echo
  EthernetTetheringTest#testVirtualEthernet
  EthernetTetheringTest#testLocalOnlyTethering
  EthernetTetheringTest#testTetherConfigBpfOffloadEnabled
  EthernetTetheringTest#testTetherClatTcp
  EthernetTetheringTest#testTetherClatUdp
  EthernetTetheringTest#testIsUdpOffloadSupportedByKernel
  EthernetTetheringTest#testTetherClatIcmp
  EthernetTetheringTest#testTetherTcpV4
  EthernetTetheringTest#testTetherTcpV6
  EthernetTetheringTest#testTetherUdpV4
  EthernetTetheringTest#testTetherUdpV6
  EthernetTetheringTest#testStaticIpv4
  EthernetTetheringTest#testKernelSupportBpfOffloadUdpV4
  EthernetTetheringTest#testVirtualEthernetAlreadyExists
  EthernetTetheringTest#testPhysicalEthernet
  EthernetTetheringTest#testTetherUdpV4_VerifyBpf
  EthernetTetheringTest#testTetherUdpV4Dns

After:
  - TetheringTests (15 tests)
  EthernetTetheringTest#testIcmpv4Echo
  EthernetTetheringTest#testIcmpv6Echo
  EthernetTetheringTest#testVirtualEthernet
  EthernetTetheringTest#testLocalOnlyTethering
  EthernetTetheringTest#testTetherClatTcp
  EthernetTetheringTest#testTetherClatUdp
  EthernetTetheringTest#testTetherClatIcmp
  EthernetTetheringTest#testTetherTcpV4
  EthernetTetheringTest#testTetherTcpV6
  EthernetTetheringTest#testTetherUdpV4
  EthernetTetheringTest#testTetherUdpV6
  EthernetTetheringTest#testStaticIpv4
  EthernetTetheringTest#testVirtualEthernetAlreadyExists
  EthernetTetheringTest#testPhysicalEthernet
  EthernetTetheringTest#testTetherUdpV4Dns

  - MTS (4 tests)
  MtsEthernetTetheringTest#testTetherConfigBpfOffloadEnabled
  MtsEthernetTetheringTest#testIsUdpOffloadSupportedByKernel
  MtsEthernetTetheringTest#testTetherBpfOffloadUdpV4
  MtsEthernetTetheringTest#testKernelSupportBpfOffloadUdpV4

  Note that MtsEthernetTetheringTest#testTetherBpfOffloadUdpV4 is
  renamed from EthernetTetheringTest#testTetherUdpV4_VerifyBpf

Bug: 250552545
Bug: 258637850
Test: atest ConnectivityCoverageTests
Test: atest CtsTetheringTest
Test: atest CtsTetheringTestLatestSdk
Test: atest MtsTetheringTestLatestSdk
Test: atest TetheringIntegrationTests
Change-Id: Ica3b7008b33b1a0ddc5789d8ef12122a38544d57
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index 11e3dc0..5e08aba 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -21,8 +21,7 @@
     name: "TetheringIntegrationTestsDefaults",
     defaults: ["framework-connectivity-test-defaults"],
     srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
+        "base/**/*.java",
     ],
     min_sdk_version: "30",
     static_libs: [
@@ -47,6 +46,16 @@
     ],
 }
 
+android_library {
+    name: "TetheringIntegrationTestsBaseLib",
+    target_sdk_version: "current",
+    platform_apis: true,
+    defaults: ["TetheringIntegrationTestsDefaults"],
+    visibility: [
+        "//packages/modules/Connectivity/Tethering/tests/mts",
+    ]
+}
+
 // Library including tethering integration tests targeting the latest stable SDK.
 // Use with NetworkStackJarJarRules.
 android_library {
@@ -54,6 +63,9 @@
     target_sdk_version: "33",
     platform_apis: true,
     defaults: ["TetheringIntegrationTestsDefaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
     visibility: [
         "//packages/modules/Connectivity/tests/cts/tethering",
         "//packages/modules/Connectivity/tests:__subpackages__",
@@ -68,12 +80,16 @@
     target_sdk_version: "current",
     platform_apis: true,
     defaults: ["TetheringIntegrationTestsDefaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
     visibility: [
         "//packages/modules/Connectivity/tests/cts/tethering",
         "//packages/modules/Connectivity/Tethering/tests/mts",
     ]
 }
 
+// TODO: remove because TetheringIntegrationTests has been covered by ConnectivityCoverageTests.
 android_test {
     name: "TetheringIntegrationTests",
     platform_apis: true,
@@ -81,6 +97,9 @@
     test_suites: [
         "device-tests",
     ],
+    srcs: [
+        "src/**/*.java",
+    ],
     compile_multilib: "both",
     jarjar_rules: ":NetworkStackJarJarRules",
 }
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/EthernetTetheringTestBase.java
rename to Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java
similarity index 100%
rename from Tethering/tests/integration/src/android/net/TetheringTester.java
rename to Tethering/tests/integration/base/android/net/TetheringTester.java
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 97a255f..fb4b9fa 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import static android.Manifest.permission.DUMP;
 import static android.net.InetAddresses.parseNumericAddress;
 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
@@ -26,7 +25,6 @@
 import static android.system.OsConstants.ICMP_ECHO;
 import static android.system.OsConstants.ICMP_ECHOREPLY;
 import static android.system.OsConstants.IPPROTO_ICMP;
-import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
 import static com.android.net.module.util.HexDump.dumpHexString;
@@ -39,39 +37,28 @@
 import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET;
 import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
 import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET;
-import static com.android.testutils.DeviceInfoUtils.KVersion;
-import static com.android.testutils.TestPermissionUtil.runAsShell;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.content.Context;
 import android.net.TetheringManager.TetheringRequest;
 import android.net.TetheringTester.TetheredDevice;
 import android.os.Build;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.VintfRuntimeInfo;
 import android.util.Log;
-import android.util.Pair;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.net.module.util.BpfDump;
 import com.android.net.module.util.Ipv6Utils;
 import com.android.net.module.util.Struct;
-import com.android.net.module.util.bpf.Tether4Key;
-import com.android.net.module.util.bpf.Tether4Value;
-import com.android.net.module.util.bpf.TetherStatsKey;
-import com.android.net.module.util.bpf.TetherStatsValue;
 import com.android.net.module.util.structs.EthernetHeader;
 import com.android.net.module.util.structs.Icmpv4Header;
 import com.android.net.module.util.structs.Ipv4Header;
@@ -79,8 +66,6 @@
 import com.android.net.module.util.structs.UdpHeader;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DeviceInfoUtils;
-import com.android.testutils.DumpTestUtils;
 import com.android.testutils.TapPacketReader;
 
 import org.junit.Rule;
@@ -96,9 +81,7 @@
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -112,28 +95,7 @@
 
     private static final String TAG = EthernetTetheringTest.class.getSimpleName();
 
-    private static final int DUMP_POLLING_MAX_RETRY = 100;
-    private static final int DUMP_POLLING_INTERVAL_MS = 50;
-    // Kernel treats a confirmed UDP connection which active after two seconds as stream mode.
-    // See upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5.
-    private static final int UDP_STREAM_TS_MS = 2000;
-    // Give slack time for waiting UDP stream mode because handling conntrack event in user space
-    // may not in precise time. Used to reduce the flaky rate.
-    private static final int UDP_STREAM_SLACK_MS = 500;
-    // Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
-    private static final int RX_UDP_PACKET_SIZE = 30;
-    private static final int RX_UDP_PACKET_COUNT = 456;
-    // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
-    private static final int TX_UDP_PACKET_SIZE = 44;
-    private static final int TX_UDP_PACKET_COUNT = 123;
-
     private static final short DNS_PORT = 53;
-
-    private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
-    private static final String DUMPSYS_RAWMAP_ARG_STATS = "--stats";
-    private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
-    private static final String LINE_DELIMITER = "\\n";
-
     private static final short ICMPECHO_CODE = 0x0;
     private static final short ICMPECHO_ID = 0x0;
     private static final short ICMPECHO_SEQ = 0x0;
@@ -529,7 +491,7 @@
     // remote ip              public ip                           private ip
     // 8.8.8.8:443            <Upstream ip>:9876                  <TetheredDevice ip>:9876
     //
-    private void runUdp4Test(boolean verifyBpf) throws Exception {
+    private void runUdp4Test() throws Exception {
         final TetheringTester tester = initTetheringTester(toList(TEST_IP4_ADDR),
                 toList(TEST_IP4_DNS));
         final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, false /* hasIpv6 */);
@@ -549,123 +511,6 @@
         final InetAddress clientIp = tethered.ipv4Addr;
         sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
         sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
-
-        if (verifyBpf) {
-            // Send second UDP packet in original direction.
-            // The BPF coordinator only offloads the ASSURED conntrack entry. The "request + reply"
-            // packets can make status IPS_SEEN_REPLY to be set. Need one more packet to make
-            // conntrack status IPS_ASSURED_BIT to be set. Note the third packet needs to delay
-            // 2 seconds because kernel monitors a UDP connection which still alive after 2 seconds
-            // and apply ASSURED flag.
-            // See kernel upstream commit b7b1d02fc43925a4d569ec221715db2dfa1ce4f5 and
-            // nf_conntrack_udp_packet in net/netfilter/nf_conntrack_proto_udp.c
-            Thread.sleep(UDP_STREAM_TS_MS);
-            sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester, false /* is4To6 */);
-
-            // Give a slack time for handling conntrack event in user space.
-            Thread.sleep(UDP_STREAM_SLACK_MS);
-
-            // [1] Verify IPv4 upstream rule map.
-            final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
-                    Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
-            assertNotNull(upstreamMap);
-            assertEquals(1, upstreamMap.size());
-
-            final Map.Entry<Tether4Key, Tether4Value> rule =
-                    upstreamMap.entrySet().iterator().next();
-
-            final Tether4Key upstream4Key = rule.getKey();
-            assertEquals(IPPROTO_UDP, upstream4Key.l4proto);
-            assertTrue(Arrays.equals(tethered.ipv4Addr.getAddress(), upstream4Key.src4));
-            assertEquals(LOCAL_PORT, upstream4Key.srcPort);
-            assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(), upstream4Key.dst4));
-            assertEquals(REMOTE_PORT, upstream4Key.dstPort);
-
-            final Tether4Value upstream4Value = rule.getValue();
-            assertTrue(Arrays.equals(tetheringUpstreamIp.getAddress(),
-                    InetAddress.getByAddress(upstream4Value.src46).getAddress()));
-            assertEquals(LOCAL_PORT, upstream4Value.srcPort);
-            assertTrue(Arrays.equals(REMOTE_IP4_ADDR.getAddress(),
-                    InetAddress.getByAddress(upstream4Value.dst46).getAddress()));
-            assertEquals(REMOTE_PORT, upstream4Value.dstPort);
-
-            // [2] Verify stats map.
-            // Transmit packets on both direction for verifying stats. Because we only care the
-            // packet count in stats test, we just reuse the existing packets to increaes
-            // the packet count on both direction.
-
-            // Send packets on original direction.
-            for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
-                sendUploadPacketUdp(srcMac, dstMac, clientIp, remoteIp, tester,
-                        false /* is4To6 */);
-            }
-
-            // Send packets on reply direction.
-            for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
-                sendDownloadPacketUdp(remoteIp, tetheringUpstreamIp, tester, false /* is6To4 */);
-            }
-
-            // Dump stats map to verify.
-            final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
-                    TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
-            assertNotNull(statsMap);
-            assertEquals(1, statsMap.size());
-
-            final Map.Entry<TetherStatsKey, TetherStatsValue> stats =
-                    statsMap.entrySet().iterator().next();
-
-            // TODO: verify the upstream index in TetherStatsKey.
-
-            final TetherStatsValue statsValue = stats.getValue();
-            assertEquals(RX_UDP_PACKET_COUNT, statsValue.rxPackets);
-            assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE, statsValue.rxBytes);
-            assertEquals(0, statsValue.rxErrors);
-            assertEquals(TX_UDP_PACKET_COUNT, statsValue.txPackets);
-            assertEquals(TX_UDP_PACKET_COUNT * TX_UDP_PACKET_SIZE, statsValue.txBytes);
-            assertEquals(0, statsValue.txErrors);
-        }
-    }
-
-    private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
-        final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
-        return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
-                || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
-                || current.isAtLeast(new KVersion(5, 4, 98));
-    }
-
-    @Test
-    public void testIsUdpOffloadSupportedByKernel() throws Exception {
-        assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
-        assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
-
-        assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
-        assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
-        assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
-
-        assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
-        assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
-    }
-
-    private static void assumeKernelSupportBpfOffloadUdpV4() {
-        final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
-        assumeTrue("Kernel version " + kernelVersion + " doesn't support IPv4 UDP BPF offload",
-                isUdpOffloadSupportedByKernel(kernelVersion));
-    }
-
-    @Test
-    public void testKernelSupportBpfOffloadUdpV4() throws Exception {
-        assumeKernelSupportBpfOffloadUdpV4();
-    }
-
-    @Test
-    public void testTetherConfigBpfOffloadEnabled() throws Exception {
-        assumeTrue(isTetherConfigBpfOffloadEnabled());
     }
 
     /**
@@ -674,73 +519,7 @@
      */
     @Test
     public void testTetherUdpV4() throws Exception {
-        runUdp4Test(false /* verifyBpf */);
-    }
-
-    /**
-     * BPF offload IPv4 UDP tethering test. Verify that UDP tethered packets are offloaded by BPF.
-     * Minimum test requirement:
-     * 1. S+ device.
-     * 2. Tethering config enables tethering BPF offload.
-     * 3. Kernel supports IPv4 UDP BPF offload. See #isUdpOffloadSupportedByKernel.
-     *
-     * TODO: consider enabling the test even tethering config disables BPF offload. See b/238288883
-     */
-    @Test
-    @IgnoreUpTo(Build.VERSION_CODES.R)
-    public void testTetherUdpV4_VerifyBpf() throws Exception {
-        assumeTrue("Tethering config disabled BPF offload", isTetherConfigBpfOffloadEnabled());
-        assumeKernelSupportBpfOffloadUdpV4();
-
-        runUdp4Test(true /* verifyBpf */);
-    }
-
-    @NonNull
-    private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
-            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
-            throws Exception {
-        final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
-        final String rawMapStr = runAsShell(DUMP, () ->
-                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
-        final HashMap<K, V> map = new HashMap<>();
-
-        for (final String line : rawMapStr.split(LINE_DELIMITER)) {
-            final Pair<K, V> rule =
-                    BpfDump.fromBase64EncodedString(keyClass, valueClass, line.trim());
-            map.put(rule.first, rule.second);
-        }
-        return map;
-    }
-
-    @Nullable
-    private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
-            Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
-            throws Exception {
-        for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
-            final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
-            if (!map.isEmpty()) return map;
-
-            Thread.sleep(DUMP_POLLING_INTERVAL_MS);
-        }
-
-        fail("Cannot get rules after " + DUMP_POLLING_MAX_RETRY * DUMP_POLLING_INTERVAL_MS + "ms");
-        return null;
-    }
-
-    private boolean isTetherConfigBpfOffloadEnabled() throws Exception {
-        final String dumpStr = runAsShell(DUMP, () ->
-                DumpTestUtils.dumpService(Context.TETHERING_SERVICE, "--short"));
-
-        // BPF offload tether config can be overridden by "config_tether_enable_bpf_offload" in
-        // packages/modules/Connectivity/Tethering/res/values/config.xml. OEM may disable config by
-        // RRO to override the enabled default value. Get the tethering config via dumpsys.
-        // $ dumpsys tethering
-        //   mIsBpfEnabled: true
-        boolean enabled = dumpStr.contains("mIsBpfEnabled: true");
-        if (!enabled) {
-            Log.d(TAG, "BPF offload tether config not enabled: " + dumpStr);
-        }
-        return enabled;
+        runUdp4Test();
     }
 
     @NonNull