Merge "Add testTetherClatBpfOffloadUdp to TetheringTest" into main
This commit is contained in:
commit
0afcda3caa
1 changed files with 103 additions and 7 deletions
|
|
@ -33,6 +33,8 @@ import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
|
|||
import static com.android.net.module.util.HexDump.dumpHexString;
|
||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE;
|
||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
|
||||
import static com.android.testutils.DeviceInfoUtils.KVersion;
|
||||
import static com.android.testutils.TestPermissionUtil.runAsShell;
|
||||
|
||||
|
|
@ -62,6 +64,10 @@ 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.ClatEgress4Key;
|
||||
import com.android.net.module.util.bpf.ClatEgress4Value;
|
||||
import com.android.net.module.util.bpf.ClatIngress6Key;
|
||||
import com.android.net.module.util.bpf.ClatIngress6Value;
|
||||
import com.android.net.module.util.bpf.Tether4Key;
|
||||
import com.android.net.module.util.bpf.Tether4Value;
|
||||
import com.android.net.module.util.bpf.TetherStatsKey;
|
||||
|
|
@ -122,6 +128,8 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
private static final int TX_UDP_PACKET_SIZE = 30;
|
||||
private static final int TX_UDP_PACKET_COUNT = 123;
|
||||
|
||||
private static final String DUMPSYS_CLAT_RAWMAP_EGRESS4_ARG = "clatEgress4RawBpfMap";
|
||||
private static final String DUMPSYS_CLAT_RAWMAP_INGRESS6_ARG = "clatIngress6RawBpfMap";
|
||||
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";
|
||||
|
|
@ -901,11 +909,10 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
|
||||
@NonNull
|
||||
private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
|
||||
Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
|
||||
Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)
|
||||
throws Exception {
|
||||
final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
|
||||
final String rawMapStr = runAsShell(DUMP, () ->
|
||||
DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args));
|
||||
DumpTestUtils.dumpService(service, args));
|
||||
final HashMap<K, V> map = new HashMap<>();
|
||||
|
||||
for (final String line : rawMapStr.split(LINE_DELIMITER)) {
|
||||
|
|
@ -918,10 +925,10 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
|
||||
@Nullable
|
||||
private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
|
||||
Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
|
||||
Class<K> keyClass, Class<V> valueClass, @NonNull String service, @NonNull String[] args)
|
||||
throws Exception {
|
||||
for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
|
||||
final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
|
||||
final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, service, args);
|
||||
if (!map.isEmpty()) return map;
|
||||
|
||||
Thread.sleep(DUMP_POLLING_INTERVAL_MS);
|
||||
|
|
@ -977,8 +984,10 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
Thread.sleep(UDP_STREAM_SLACK_MS);
|
||||
|
||||
// [1] Verify IPv4 upstream rule map.
|
||||
final String[] upstreamArgs = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG,
|
||||
DUMPSYS_RAWMAP_ARG_UPSTREAM4};
|
||||
final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
|
||||
Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
|
||||
Tether4Key.class, Tether4Value.class, Context.TETHERING_SERVICE, upstreamArgs);
|
||||
assertNotNull(upstreamMap);
|
||||
assertEquals(1, upstreamMap.size());
|
||||
|
||||
|
|
@ -1017,8 +1026,10 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
}
|
||||
|
||||
// Dump stats map to verify.
|
||||
final String[] statsArgs = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG,
|
||||
DUMPSYS_RAWMAP_ARG_STATS};
|
||||
final HashMap<TetherStatsKey, TetherStatsValue> statsMap = pollRawMapFromDump(
|
||||
TetherStatsKey.class, TetherStatsValue.class, DUMPSYS_RAWMAP_ARG_STATS);
|
||||
TetherStatsKey.class, TetherStatsValue.class, Context.TETHERING_SERVICE, statsArgs);
|
||||
assertNotNull(statsMap);
|
||||
assertEquals(1, statsMap.size());
|
||||
|
||||
|
|
@ -1053,4 +1064,89 @@ public class EthernetTetheringTest extends EthernetTetheringTestBase {
|
|||
|
||||
runUdp4Test();
|
||||
}
|
||||
|
||||
private ClatEgress4Value getClatEgress4Value() throws Exception {
|
||||
// Command: dumpsys connectivity clatEgress4RawBpfMap
|
||||
final String[] args = new String[] {DUMPSYS_CLAT_RAWMAP_EGRESS4_ARG};
|
||||
final HashMap<ClatEgress4Key, ClatEgress4Value> egress4Map = pollRawMapFromDump(
|
||||
ClatEgress4Key.class, ClatEgress4Value.class, Context.CONNECTIVITY_SERVICE, args);
|
||||
assertNotNull(egress4Map);
|
||||
assertEquals(1, egress4Map.size());
|
||||
return egress4Map.entrySet().iterator().next().getValue();
|
||||
}
|
||||
|
||||
private ClatIngress6Value getClatIngress6Value() throws Exception {
|
||||
// Command: dumpsys connectivity clatIngress6RawBpfMap
|
||||
final String[] args = new String[] {DUMPSYS_CLAT_RAWMAP_INGRESS6_ARG};
|
||||
final HashMap<ClatIngress6Key, ClatIngress6Value> ingress6Map = pollRawMapFromDump(
|
||||
ClatIngress6Key.class, ClatIngress6Value.class, Context.CONNECTIVITY_SERVICE, args);
|
||||
assertNotNull(ingress6Map);
|
||||
assertEquals(1, ingress6Map.size());
|
||||
return ingress6Map.entrySet().iterator().next().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test network topology:
|
||||
*
|
||||
* public network (rawip) private network
|
||||
* | UE (CLAT support) |
|
||||
* +---------------+ V +------------+------------+ V +------------+
|
||||
* | NAT64 Gateway +---------+ Upstream | Downstream +---------+ Client |
|
||||
* +---------------+ +------------+------------+ +------------+
|
||||
* remote ip public ip private ip
|
||||
* [64:ff9b::808:808]:443 [clat ipv6]:9876 [TetheredDevice ipv4]:9876
|
||||
*
|
||||
* Note that CLAT IPv6 address is generated by ClatCoordinator. Get the CLAT IPv6 address by
|
||||
* sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
|
||||
* packet.
|
||||
*/
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testTetherClatBpfOffloadUdp() throws Exception {
|
||||
assumeKernelSupportBpfOffloadUdpV4();
|
||||
|
||||
// CLAT only starts on IPv6 only network.
|
||||
final TetheringTester tester = initTetheringTester(toList(TEST_IP6_ADDR),
|
||||
toList(TEST_IP6_DNS));
|
||||
final TetheredDevice tethered = tester.createTetheredDevice(TEST_MAC, true /* hasIpv6 */);
|
||||
|
||||
// Get CLAT IPv6 address.
|
||||
final Inet6Address clatIp6 = getClatIpv6Address(tester, tethered);
|
||||
|
||||
// Get current values before sending packets.
|
||||
final ClatEgress4Value oldEgress4 = getClatEgress4Value();
|
||||
final ClatIngress6Value oldIngress6 = getClatIngress6Value();
|
||||
|
||||
// Send an IPv4 UDP packet in original direction.
|
||||
// IPv4 packet -- CLAT translation --> IPv6 packet
|
||||
for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
|
||||
sendUploadPacketUdp(tethered.macAddr, tethered.routerMacAddr, tethered.ipv4Addr,
|
||||
REMOTE_IP4_ADDR, tester, true /* is4To6 */);
|
||||
}
|
||||
|
||||
// Send an IPv6 UDP packet in reply direction.
|
||||
// IPv6 packet -- CLAT translation --> IPv4 packet
|
||||
for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
|
||||
sendDownloadPacketUdp(REMOTE_NAT64_ADDR, clatIp6, tester, true /* is6To4 */);
|
||||
}
|
||||
|
||||
// After sending test packets, get stats again to verify their differences.
|
||||
final ClatEgress4Value newEgress4 = getClatEgress4Value();
|
||||
final ClatIngress6Value newIngress6 = getClatIngress6Value();
|
||||
|
||||
assertEquals(RX_UDP_PACKET_COUNT, newIngress6.packets - oldIngress6.packets);
|
||||
assertEquals(RX_UDP_PACKET_COUNT * RX_UDP_PACKET_SIZE,
|
||||
newIngress6.bytes - oldIngress6.bytes);
|
||||
assertEquals(TX_UDP_PACKET_COUNT, newEgress4.packets - oldEgress4.packets);
|
||||
// The increase in egress traffic equals the expected size of the translated UDP packets.
|
||||
// Calculation:
|
||||
// - Original UDP packet was TX_UDP_PACKET_SIZE bytes (IPv4 header + UDP header + payload).
|
||||
// - After CLAT translation, each packet is now:
|
||||
// IPv6 header + unchanged UDP header + unchanged payload
|
||||
// Therefore, the total size of the translated UDP packet should be:
|
||||
// TX_UDP_PACKET_SIZE + IPV6_HEADER_LEN - IPV4_HEADER_MIN_LEN
|
||||
assertEquals(
|
||||
TX_UDP_PACKET_COUNT * (TX_UDP_PACKET_SIZE + IPV6_HEADER_LEN - IPV4_HEADER_MIN_LEN),
|
||||
newEgress4.bytes - oldEgress4.bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue