Merge "[TestOnly]Remove RemoteResponder from TetheringTester"

This commit is contained in:
Treehugger Robot
2022-06-13 11:59:54 +00:00
committed by Gerrit Code Review
2 changed files with 71 additions and 71 deletions

View File

@@ -26,7 +26,6 @@ import static android.net.InetAddresses.parseNumericAddress;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringTester.RemoteResponder;
import static android.net.TetheringTester.isIcmpv6Type;
import static android.system.OsConstants.IPPROTO_IP;
import static android.system.OsConstants.IPPROTO_IPV6;
@@ -816,10 +815,10 @@ public class EthernetTetheringTest {
mDownstreamReader = makePacketReader(mDownstreamIface);
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
runPing6Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader));
runPing6Test(new TetheringTester(mDownstreamReader, mUpstreamReader));
}
private void runPing6Test(TetheringTester tester, RemoteResponder remote) throws Exception {
private void runPing6Test(TetheringTester tester) throws Exception {
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
@@ -830,24 +829,18 @@ public class EthernetTetheringTest {
Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
tester.sendPacket(request);
final byte[] echoRequest = remote.getNextMatchedPacket((p) -> {
tester.verifyUpload(request, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
});
assertNotNull("No icmpv6 echo request in upstream", echoRequest);
ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
remote.sendPacket(reply);
final byte[] echoReply = tester.getNextMatchedPacket((p) -> {
tester.verifyDownload(reply, p -> {
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
});
assertNotNull("No icmpv6 echo reply in downstream", echoReply);
}
// Test network topology:
@@ -964,7 +957,7 @@ public class EthernetTetheringTest {
// TODO: remove this verification once upstream connected notification race is fixed.
// See #runUdp4Test.
private boolean isIpv4TetherConnectivityVerified(TetheringTester tester,
RemoteResponder remote, TetheredDevice tethered) throws Exception {
TetheredDevice tethered) throws Exception {
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
@@ -972,8 +965,7 @@ public class EthernetTetheringTest {
// Send a UDP packet from client and check the packet can be found on upstream interface.
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
tester.sendPacket(probePacket);
byte[] expectedPacket = remote.getNextMatchedPacket(p -> {
byte[] expectedPacket = tester.testUpload(probePacket, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */,
TEST_REACHABILITY_PAYLOAD);
@@ -983,8 +975,7 @@ public class EthernetTetheringTest {
return false;
}
private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)
throws Exception {
private void runUdp4Test(TetheringTester tester, boolean usingBpf) throws Exception {
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
"1:2:3:4:5:6"), false /* hasIpv6 */);
@@ -994,14 +985,14 @@ public class EthernetTetheringTest {
// For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
// from upstream. That can guarantee that the routing is ready. Long term plan is that
// refactors upstream connected notification from async to sync.
assertTrue(isIpv4TetherConnectivityVerified(tester, remote, tethered));
assertTrue(isIpv4TetherConnectivityVerified(tester, tethered));
// Send a UDP packet in original direction.
final ByteBuffer originalPacket = buildUdpPacket(tethered.macAddr,
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
PAYLOAD /* payload */);
tester.verifyUpload(remote, originalPacket, p -> {
tester.verifyUpload(originalPacket, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
});
@@ -1011,7 +1002,7 @@ public class EthernetTetheringTest {
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_IP4_ADDR /* srcIp */,
publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
PAYLOAD2 /* payload */);
remote.verifyDownload(tester, replyPacket, p -> {
tester.verifyDownload(replyPacket, p -> {
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
});
@@ -1030,7 +1021,7 @@ public class EthernetTetheringTest {
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
REMOTE_PORT /* dstPort */, PAYLOAD3 /* payload */);
tester.verifyUpload(remote, originalPacket2, p -> {
tester.verifyUpload(originalPacket2, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD3);
});
@@ -1066,7 +1057,7 @@ public class EthernetTetheringTest {
// Send packets on original direction.
for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
tester.verifyUpload(remote, originalPacket, p -> {
tester.verifyUpload(originalPacket, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
});
@@ -1074,7 +1065,7 @@ public class EthernetTetheringTest {
// Send packets on reply direction.
for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
remote.verifyDownload(tester, replyPacket, p -> {
tester.verifyDownload(replyPacket, p -> {
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
});
@@ -1130,8 +1121,7 @@ public class EthernetTetheringTest {
@IgnoreAfter(Build.VERSION_CODES.R)
public void testTetherUdpV4UpToR() throws Exception {
initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
false /* usingBpf */);
runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), false /* usingBpf */);
}
private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
@@ -1172,8 +1162,7 @@ public class EthernetTetheringTest {
Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
+ kernelVersion);
}
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
usingBpf);
runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), usingBpf);
}
@Nullable
@@ -1233,8 +1222,8 @@ public class EthernetTetheringTest {
}
@Nullable
private Inet6Address getClatIpv6Address(TetheringTester tester,
RemoteResponder remote, TetheredDevice tethered) throws Exception {
private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)
throws Exception {
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
@@ -1245,8 +1234,7 @@ public class EthernetTetheringTest {
// packet.
byte[] expectedPacket = null;
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
tester.sendPacket(probePacket);
expectedPacket = remote.getNextMatchedPacket(p -> {
expectedPacket = tester.verifyUpload(probePacket, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */,
TEST_REACHABILITY_PAYLOAD);
@@ -1275,8 +1263,7 @@ public class EthernetTetheringTest {
// sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
// packet.
//
private void runClatUdpTest(TetheringTester tester, RemoteResponder remote)
throws Exception {
private void runClatUdpTest(TetheringTester tester) throws Exception {
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
@@ -1286,7 +1273,7 @@ public class EthernetTetheringTest {
"1:2:3:4:5:6"), true /* hasIpv6 */);
// Get CLAT IPv6 address.
final Inet6Address clatAddr6 = getClatIpv6Address(tester, remote, tethered);
final Inet6Address clatAddr6 = getClatIpv6Address(tester, tethered);
assertNotNull(clatAddr6);
// Send an IPv4 UDP packet in original direction.
@@ -1295,7 +1282,7 @@ public class EthernetTetheringTest {
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
PAYLOAD /* payload */);
tester.verifyUpload(remote, originalPacket, p -> {
tester.verifyUpload(originalPacket, p -> {
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, PAYLOAD);
});
@@ -1305,7 +1292,7 @@ public class EthernetTetheringTest {
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_NAT64_ADDR /* srcIp */,
clatAddr6 /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
PAYLOAD2 /* payload */);
remote.verifyDownload(tester, replyPacket, p -> {
tester.verifyDownload(replyPacket, p -> {
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
});
@@ -1318,8 +1305,7 @@ public class EthernetTetheringTest {
public void testTetherClatUdp() throws Exception {
// CLAT only starts on IPv6 only network.
initializeTethering(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS));
runClatUdpTest(new TetheringTester(mDownstreamReader),
new RemoteResponder(mUpstreamReader));
runClatUdpTest(new TetheringTester(mDownstreamReader, mUpstreamReader));
}
private <T> List<T> toList(T... array) {

View File

@@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.net.module.util.Ipv6Utils;
@@ -88,11 +89,17 @@ public final class TetheringTester {
private final ArrayMap<MacAddress, TetheredDevice> mTetheredDevices;
private final TapPacketReader mDownstreamReader;
private final TapPacketReader mUpstreamReader;
public TetheringTester(TapPacketReader downstream) {
this(downstream, null);
}
public TetheringTester(TapPacketReader downstream, TapPacketReader upstream) {
if (downstream == null) fail("Downstream reader could not be NULL");
mDownstreamReader = downstream;
mUpstreamReader = upstream;
mTetheredDevices = new ArrayMap<>();
}
@@ -170,7 +177,7 @@ public final class TetheringTester {
}
private DhcpPacket getNextDhcpPacket() throws Exception {
final byte[] packet = getNextMatchedPacket((p) -> {
final byte[] packet = getDownloadPacket((p) -> {
// Test whether this is DHCP packet.
try {
DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
@@ -213,7 +220,7 @@ public final class TetheringTester {
tethered.ipv4Addr.getAddress() /* sender IP */,
(short) ARP_REPLY);
try {
sendPacket(arpReply);
sendUploadPacket(arpReply);
} catch (Exception e) {
fail("Failed to reply ARP for " + tethered.ipv4Addr);
}
@@ -227,9 +234,9 @@ public final class TetheringTester {
tetherMac.toByteArray() /* srcMac */, routerIp.getAddress() /* target IP */,
new byte[ETHER_ADDR_LEN] /* target HW address */,
tetherIp.getAddress() /* sender IP */, (short) ARP_REQUEST);
sendPacket(arpProbe);
sendUploadPacket(arpProbe);
final byte[] packet = getNextMatchedPacket((p) -> {
final byte[] packet = getDownloadPacket((p) -> {
final ArpPacket arpPacket = parseArpPacket(p);
if (arpPacket == null || arpPacket.opCode != ARP_REPLY) return false;
return arpPacket.targetIp.equals(tetherIp);
@@ -252,7 +259,7 @@ public final class TetheringTester {
// connectivity is ready. We don't extract the router mac address from RA because
// we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp.
for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
final byte[] raPacket = getNextMatchedPacket((p) -> {
final byte[] raPacket = getDownloadPacket((p) -> {
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
});
if (raPacket != null) return;
@@ -290,13 +297,10 @@ public final class TetheringTester {
private Inet6Address runSlaac(MacAddress srcMac, MacAddress dstMac) throws Exception {
sendRsPacket(srcMac, dstMac);
final byte[] raPacket = getNextMatchedPacket((p) -> {
final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
});
}));
if (raPacket == null) {
fail("Could not get ra for prefix options");
}
final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
for (PrefixInformationOption pio : options) {
@@ -322,7 +326,7 @@ public final class TetheringTester {
ByteBuffer rs = Ipv6Utils.buildRsPacket(srcMac, dstMac, (Inet6Address) LINK_LOCAL,
IPV6_ADDR_ALL_NODES_MULTICAST, slla);
sendPacket(rs);
sendUploadPacket(rs);
}
private void maybeReplyNa(byte[] packet) {
@@ -347,7 +351,7 @@ public final class TetheringTester {
ByteBuffer ns = Ipv6Utils.buildNaPacket(tethered.macAddr, tethered.routerMacAddr,
nsHdr.target, ipv6Hdr.srcIp, flags, nsHdr.target, tlla);
try {
sendPacket(ns);
sendUploadPacket(ns);
} catch (Exception e) {
fail("Failed to reply NA for " + tethered.ipv6Addr);
}
@@ -380,11 +384,17 @@ public final class TetheringTester {
return false;
}
public void sendPacket(ByteBuffer packet) throws Exception {
private void sendUploadPacket(ByteBuffer packet) throws Exception {
mDownstreamReader.sendResponse(packet);
}
public byte[] getNextMatchedPacket(Predicate<byte[]> filter) {
private void sendDownloadPacket(ByteBuffer packet) throws Exception {
assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
mUpstreamReader.sendResponse(packet);
}
private byte[] getDownloadPacket(Predicate<byte[]> filter) {
byte[] packet;
while ((packet = mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS)) != null) {
if (filter.test(packet)) return packet;
@@ -396,30 +406,34 @@ public final class TetheringTester {
return null;
}
public void verifyUpload(final RemoteResponder dst, final ByteBuffer packet,
final Predicate<byte[]> filter) throws Exception {
sendPacket(packet);
assertNotNull("Upload fail", dst.getNextMatchedPacket(filter));
private byte[] getUploadPacket(Predicate<byte[]> filter) {
assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
}
public static class RemoteResponder {
final TapPacketReader mUpstreamReader;
public RemoteResponder(TapPacketReader reader) {
mUpstreamReader = reader;
}
private @NonNull byte[] verifyPacketNotNull(String message, @Nullable byte[] packet) {
assertNotNull(message, packet);
public void sendPacket(ByteBuffer packet) throws Exception {
mUpstreamReader.sendResponse(packet);
}
return packet;
}
public byte[] getNextMatchedPacket(Predicate<byte[]> filter) throws Exception {
return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
}
public byte[] testUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
throws Exception {
sendUploadPacket(packet);
public void verifyDownload(final TetheringTester dst, final ByteBuffer packet,
final Predicate<byte[]> filter) throws Exception {
sendPacket(packet);
assertNotNull("Download fail", dst.getNextMatchedPacket(filter));
}
return getUploadPacket(filter);
}
public byte[] verifyUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
throws Exception {
return verifyPacketNotNull("Upload fail", testUpload(packet, filter));
}
public byte[] verifyDownload(final ByteBuffer packet, final Predicate<byte[]> filter)
throws Exception {
sendDownloadPacket(packet);
return verifyPacketNotNull("Download fail", getDownloadPacket(filter));
}
}