Merge "ApfTest: fix flaky testApfFilterRa."

This commit is contained in:
Hugo Benichi
2017-01-31 05:53:51 +00:00
committed by Gerrit Code Review
2 changed files with 63 additions and 41 deletions

View File

@@ -286,7 +286,8 @@ public class ApfFilter {
} }
// Returns seconds since device boot. // Returns seconds since device boot.
private static long curTime() { @VisibleForTesting
protected long currentTimeSeconds() {
return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS; return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
} }
@@ -450,7 +451,7 @@ public class ApfFilter {
} }
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
mLastSeen = curTime(); mLastSeen = currentTimeSeconds();
// Sanity check packet in case a packet arrives before we attach RA filter // Sanity check packet in case a packet arrives before we attach RA filter
// to our packet socket. b/29586253 // to our packet socket. b/29586253
@@ -580,7 +581,7 @@ public class ApfFilter {
// How many seconds does this RA's have to live, taking into account the fact // How many seconds does this RA's have to live, taking into account the fact
// that we might have seen it a while ago. // that we might have seen it a while ago.
long currentLifetime() { long currentLifetime() {
return mMinLifetime - (curTime() - mLastSeen); return mMinLifetime - (currentTimeSeconds() - mLastSeen);
} }
boolean isExpired() { boolean isExpired() {
@@ -946,7 +947,7 @@ public class ApfFilter {
Log.e(TAG, "Failed to generate APF program.", e); Log.e(TAG, "Failed to generate APF program.", e);
return; return;
} }
mLastTimeInstalledProgram = curTime(); mLastTimeInstalledProgram = currentTimeSeconds();
mLastInstalledProgramMinLifetime = programMinLifetime; mLastInstalledProgramMinLifetime = programMinLifetime;
mLastInstalledProgram = program; mLastInstalledProgram = program;
mNumProgramUpdates++; mNumProgramUpdates++;
@@ -965,7 +966,7 @@ public class ApfFilter {
*/ */
private boolean shouldInstallnewProgram() { private boolean shouldInstallnewProgram() {
long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime; long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
return expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING; return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
} }
private void hexDump(String msg, byte[] packet, int length) { private void hexDump(String msg, byte[] packet, int length) {
@@ -999,7 +1000,7 @@ public class ApfFilter {
if (ra.matches(packet, length)) { if (ra.matches(packet, length)) {
if (VDBG) log("matched RA " + ra); if (VDBG) log("matched RA " + ra);
// Update lifetimes. // Update lifetimes.
ra.mLastSeen = curTime(); ra.mLastSeen = currentTimeSeconds();
ra.mMinLifetime = ra.minLifetime(packet, length); ra.mMinLifetime = ra.minLifetime(packet, length);
ra.seenCount++; ra.seenCount++;
@@ -1128,7 +1129,7 @@ public class ApfFilter {
pw.println("Program updates: " + mNumProgramUpdates); pw.println("Program updates: " + mNumProgramUpdates);
pw.println(String.format( pw.println(String.format(
"Last program length %d, installed %ds ago, lifetime %ds", "Last program length %d, installed %ds ago, lifetime %ds",
mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram, mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
mLastInstalledProgramMinLifetime)); mLastInstalledProgramMinLifetime));
pw.println("RA filters:"); pw.println("RA filters:");
@@ -1137,7 +1138,7 @@ public class ApfFilter {
pw.println(ra); pw.println(ra);
pw.increaseIndent(); pw.increaseIndent();
pw.println(String.format( pw.println(String.format(
"Seen: %d, last %ds ago", ra.seenCount, curTime() - ra.mLastSeen)); "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
if (DBG) { if (DBG) {
pw.println("Last match:"); pw.println("Last match:");
pw.increaseIndent(); pw.increaseIndent();

View File

@@ -29,9 +29,11 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent; import android.net.metrics.RaEvent;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.SystemClock;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import android.text.format.DateUtils;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import static android.system.OsConstants.*; import static android.system.OsConstants.*;
@@ -604,6 +606,8 @@ public class ApfTest extends AndroidTestCase {
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6}; public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
private FileDescriptor mWriteSocket; private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter, public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
IpConnectivityLog log) throws Exception { IpConnectivityLog log) throws Exception {
super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"), super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
@@ -616,6 +620,11 @@ public class ApfTest extends AndroidTestCase {
Os.write(mWriteSocket, packet, 0, packet.length); Os.write(mWriteSocket, packet, 0, packet.length);
} }
@Override
protected long currentTimeSeconds() {
return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
}
@Override @Override
void maybeStartFilter() { void maybeStartFilter() {
mHardwareAddress = MOCK_MAC_ADDR; mHardwareAddress = MOCK_MAC_ADDR;
@@ -969,27 +978,30 @@ public class ApfTest extends AndroidTestCase {
// Verify that the last program pushed to the IpManager.Callback properly filters the // Verify that the last program pushed to the IpManager.Callback properly filters the
// given packet for the given lifetime. // given packet for the given lifetime.
private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet, private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
int lifetime) { final int FRACTION_OF_LIFETIME = 6;
byte[] program = ipManagerCallback.getApfProgram(); final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
// Verify new program should drop RA for 1/6th its lifetime // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
assertDrop(program, packet.array()); assertDrop(program, packet.array());
assertDrop(program, packet.array(), lifetime/6); assertDrop(program, packet.array(), ageLimit);
assertPass(program, packet.array(), lifetime/6 + 1); assertPass(program, packet.array(), ageLimit + 1);
assertPass(program, packet.array(), lifetime); assertPass(program, packet.array(), lifetime);
// Verify RA checksum is ignored // Verify RA checksum is ignored
final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345); packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
assertDrop(program, packet.array()); assertDrop(program, packet.array());
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345); packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
assertDrop(program, packet.array()); assertDrop(program, packet.array());
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
// Verify other changes to RA make it not match filter // Verify other changes to RA make it not match filter
final byte originalFirstByte = packet.get(0);
packet.put(0, (byte)-1); packet.put(0, (byte)-1);
assertPass(program, packet.array()); assertPass(program, packet.array());
packet.put(0, (byte)0); packet.put(0, (byte)0);
assertDrop(program, packet.array()); assertDrop(program, packet.array());
packet.put(0, originalFirstByte);
} }
// Test that when ApfFilter is shown the given packet, it generates a program to filter it // Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -999,9 +1011,8 @@ public class ApfTest extends AndroidTestCase {
// Verify new program generated if ApfFilter witnesses RA // Verify new program generated if ApfFilter witnesses RA
ipManagerCallback.resetApfProgramWait(); ipManagerCallback.resetApfProgramWait();
apfFilter.pretendPacketReceived(packet.array()); apfFilter.pretendPacketReceived(packet.array());
ipManagerCallback.getApfProgram(); byte[] program = ipManagerCallback.getApfProgram();
verifyRaLifetime(program, packet, lifetime);
verifyRaLifetime(ipManagerCallback, packet, lifetime);
} }
private void verifyRaEvent(RaEvent expected) { private void verifyRaEvent(RaEvent expected) {
@@ -1046,18 +1057,26 @@ public class ApfTest extends AndroidTestCase {
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram(); byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
final int PREFIX_VALID_LIFETIME = 200;
final int PREFIX_PREFERRED_LIFETIME = 100;
final int RDNSS_LIFETIME = 300;
final int ROUTE_LIFETIME = 400;
// Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
final int DNSSL_LIFETIME = 2000;
// Verify RA is passed the first time // Verify RA is passed the first time
ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT); basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000); basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
basePacket.position(IPV6_DEST_ADDR_OFFSET); basePacket.position(IPV6_DEST_ADDR_OFFSET);
basePacket.put(IPV6_ALL_NODES_ADDRESS); basePacket.put(IPV6_ALL_NODES_ADDRESS);
assertPass(program, basePacket.array()); assertPass(program, basePacket.array());
testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1)); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
// Ensure zero-length options cause the packet to be silently skipped. // Ensure zero-length options cause the packet to be silently skipped.
// Do this before we test other packets. http://b/29586253 // Do this before we test other packets. http://b/29586253
@@ -1079,11 +1098,14 @@ public class ApfTest extends AndroidTestCase {
prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8)); prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
prefixOptionPacket.putInt( prefixOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100); ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
PREFIX_PREFERRED_LIFETIME);
prefixOptionPacket.putInt( prefixOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200); ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100); PREFIX_VALID_LIFETIME);
verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1)); testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
verifyRaEvent(new RaEvent(
ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1092,9 +1114,9 @@ public class ApfTest extends AndroidTestCase {
rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE); rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
rdnssOptionPacket.putInt( rdnssOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300); ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300); testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1)); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1103,9 +1125,9 @@ public class ApfTest extends AndroidTestCase {
routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE); routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
routeInfoOptionPacket.putInt( routeInfoOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400); ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400); testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1)); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1114,18 +1136,17 @@ public class ApfTest extends AndroidTestCase {
dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE); dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
dnsslOptionPacket.putInt( dnsslOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000); ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
// Note that lifetime of 2000 will be ignored in favor of shorter testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
// route lifetime of 1000. verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
// Verify that current program filters all five RAs: // Verify that current program filters all five RAs:
verifyRaLifetime(ipManagerCallback, basePacket, 1000); program = ipManagerCallback.getApfProgram();
verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100); verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300); verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400); verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000); verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
apfFilter.shutdown(); apfFilter.shutdown();
} }