Merge "IpConn metrics: use @IntDef" into nyc-mr1-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 9d07e84..b0fb9f3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -26063,6 +26063,7 @@
method public static void logStateEvent(java.lang.String, java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.DhcpClientEvent> CREATOR;
+ field public final int durationMs;
field public final java.lang.String ifName;
field public final java.lang.String msg;
}
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 3fe68b4..169f571 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -21,36 +21,43 @@
import android.os.Parcelable;
/**
+ * An event recorded when a DhcpClient state machine transitions to a new state.
* {@hide}
*/
@SystemApi
public final class DhcpClientEvent implements Parcelable {
public final String ifName;
public final String msg;
+ public final int durationMs;
/** {@hide} */
- public DhcpClientEvent(String ifName, String msg) {
+ public DhcpClientEvent(String ifName, String msg, int durationMs) {
this.ifName = ifName;
this.msg = msg;
+ this.durationMs = durationMs;
}
private DhcpClientEvent(Parcel in) {
this.ifName = in.readString();
this.msg = in.readString();
+ this.durationMs = in.readInt();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeString(msg);
+ out.writeInt(durationMs);
}
+ @Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
- return String.format("DhcpClientEvent(%s, %s)", ifName, msg);
+ return String.format("DhcpClientEvent(%s, %s, %dms)", ifName, msg, durationMs);
}
public static final Parcelable.Creator<DhcpClientEvent> CREATOR
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index 69013c0..91bd023 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -27,6 +27,9 @@
@SystemApi
public final class RaEvent implements Parcelable {
+ /** {@hide} */
+ public static final long NO_LIFETIME = -1L;
+
// Lifetime in seconds of options found in a single RA packet.
// When an option is not set, the value of the associated field is -1;
public final long routerLifetime;
@@ -92,4 +95,60 @@
return new RaEvent[size];
}
};
+
+ /** {@hide} */
+ public static class Builder {
+
+ long routerLifetime = NO_LIFETIME;
+ long prefixValidLifetime = NO_LIFETIME;
+ long prefixPreferredLifetime = NO_LIFETIME;
+ long routeInfoLifetime = NO_LIFETIME;
+ long rdnssLifetime = NO_LIFETIME;
+ long dnsslLifetime = NO_LIFETIME;
+
+ public Builder() {
+ }
+
+ public RaEvent build() {
+ return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime,
+ routeInfoLifetime, rdnssLifetime, dnsslLifetime);
+ }
+
+ public Builder updateRouterLifetime(long lifetime) {
+ routerLifetime = updateLifetime(routerLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updatePrefixValidLifetime(long lifetime) {
+ prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updatePrefixPreferredLifetime(long lifetime) {
+ prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateRouteInfoLifetime(long lifetime) {
+ routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateRdnssLifetime(long lifetime) {
+ rdnssLifetime = updateLifetime(rdnssLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateDnsslLifetime(long lifetime) {
+ dnsslLifetime = updateLifetime(dnsslLifetime, lifetime);
+ return this;
+ }
+
+ private long updateLifetime(long currentLifetime, long newLifetime) {
+ if (currentLifetime == RaEvent.NO_LIFETIME) {
+ return newLifetime;
+ }
+ return Math.min(currentLifetime, newLifetime);
+ }
+ }
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 0ef9d7a..57f784a 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -213,7 +213,7 @@
private final ApfCapabilities mApfCapabilities;
private final IpManager.Callback mIpManagerCallback;
private final NetworkInterface mNetworkInterface;
- private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+ private final IpConnectivityLog mMetricsLog;
@VisibleForTesting
byte[] mHardwareAddress;
@VisibleForTesting
@@ -228,11 +228,12 @@
@VisibleForTesting
ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
- IpManager.Callback ipManagerCallback, boolean multicastFilter) {
+ IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) {
mApfCapabilities = apfCapabilities;
mIpManagerCallback = ipManagerCallback;
mNetworkInterface = networkInterface;
mMulticastFilter = multicastFilter;
+ mMetricsLog = log;
maybeStartFilter();
}
@@ -371,6 +372,14 @@
return i & 0xffffffffL;
}
+ private long getUint16(ByteBuffer buffer, int position) {
+ return uint16(buffer.getShort(position));
+ }
+
+ private long getUint32(ByteBuffer buffer, int position) {
+ return uint32(buffer.getInt(position));
+ }
+
private void prefixOptionToString(StringBuffer sb, int offset) {
String prefix = IPv6AddresstoString(offset + 16);
int length = uint8(mPacket.get(offset + 2));
@@ -417,7 +426,7 @@
* @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
* @param lifetimeLength length of the next lifetime data.
* @return offset within packet of where the next binary range of data not including
- * a lifetime. This can be passed into the next invocation of this function
+ * a lifetime. This can be passed into the next invocation of this function
* via {@code lastNonLifetimeStart}.
*/
private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
@@ -438,9 +447,9 @@
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
// specifications.
Ra(byte[] packet, int length) {
- mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length));
- mPacket.clear();
+ mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
mLastSeen = curTime();
+ RaEvent.Builder builder = new RaEvent.Builder();
// Ignore the checksum.
int lastNonLifetimeStart = addNonLifetime(0,
@@ -451,14 +460,7 @@
lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
ICMP6_RA_ROUTER_LIFETIME_OFFSET,
ICMP6_RA_ROUTER_LIFETIME_LEN);
-
- long routerLifetime = uint16(mPacket.getShort(
- ICMP6_RA_ROUTER_LIFETIME_OFFSET + mPacket.position()));
- long prefixValidLifetime = -1L;
- long prefixPreferredLifetime = -1L;
- long routeInfoLifetime = -1L;
- long dnsslLifetime = - 1L;
- long rdnssLifetime = -1L;
+ builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
// Ensures that the RA is not truncated.
mPacket.position(ICMP6_RA_OPTION_OFFSET);
@@ -466,39 +468,42 @@
final int position = mPacket.position();
final int optionType = uint8(mPacket.get(position));
final int optionLength = uint8(mPacket.get(position + 1)) * 8;
+ long lifetime;
switch (optionType) {
case ICMP6_PREFIX_OPTION_TYPE:
// Parse valid lifetime
lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+ lifetime = getUint32(mPacket,
+ position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
+ builder.updatePrefixValidLifetime(lifetime);
// Parse preferred lifetime
lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
+ lifetime = getUint32(mPacket,
+ position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
+ builder.updatePrefixPreferredLifetime(lifetime);
mPrefixOptionOffsets.add(position);
- prefixValidLifetime = uint32(mPacket.getInt(
- ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET + position));
- prefixPreferredLifetime = uint32(mPacket.getInt(
- ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET + position));
break;
// These three options have the same lifetime offset and size, and
- // are processed with the same specialized addNonLifetime4B:
+ // are processed with the same specialized addNonLifetimeU32:
case ICMP6_RDNSS_OPTION_TYPE:
mRdnssOptionOffsets.add(position);
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
- rdnssLifetime =
- uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
+ lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+ builder.updateRdnssLifetime(lifetime);
break;
case ICMP6_ROUTE_INFO_OPTION_TYPE:
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
- routeInfoLifetime =
- uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
+ lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+ builder.updateRouteInfoLifetime(lifetime);
break;
case ICMP6_DNSSL_OPTION_TYPE:
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
- dnsslLifetime =
- uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
+ lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+ builder.updateDnsslLifetime(lifetime);
break;
default:
// RFC4861 section 4.2 dictates we ignore unknown options for fowards
@@ -514,9 +519,7 @@
// Mark non-lifetime bytes since last lifetime.
addNonLifetime(lastNonLifetimeStart, 0, 0);
mMinLifetime = minLifetime(packet, length);
- // TODO: record per-option minimum lifetimes instead of last seen lifetimes
- mMetricsLog.log(new RaEvent(routerLifetime, prefixValidLifetime,
- prefixPreferredLifetime, routeInfoLifetime, rdnssLifetime, dnsslLifetime));
+ mMetricsLog.log(builder.build());
}
// Ignoring lifetimes (which may change) does {@code packet} match this RA?
@@ -1000,7 +1003,8 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter);
+ return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
+ multicastFilter, new IpConnectivityLog());
}
public synchronized void shutdown() {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 5852626..83cfc01 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -492,10 +492,19 @@
}
abstract class LoggingState extends State {
+ private long mEnterTimeMs;
+
@Override
public void enter() {
if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
- mMetricsLog.log(new DhcpClientEvent(mIfaceName, getName()));
+ mEnterTimeMs = SystemClock.elapsedRealtime();
+ // TODO: record time for Init -> Bound and Bound -> Renewing -> Bound
+ }
+
+ @Override
+ public void exit() {
+ long durationMs = SystemClock.elapsedRealtime() - mEnterTimeMs;
+ mMetricsLog.log(new DhcpClientEvent(mIfaceName, getName(), (int) durationMs));
}
private String messageName(int what) {
@@ -520,6 +529,13 @@
}
return NOT_HANDLED;
}
+
+ @Override
+ public String getName() {
+ // All DhcpClient's states are inner classes with a well defined name.
+ // Use getSimpleName() and avoid super's getName() creating new String instances.
+ return getClass().getSimpleName();
+ }
}
// Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
@@ -546,10 +562,9 @@
}
}
- class StoppedState extends LoggingState {
+ class StoppedState extends State {
@Override
public boolean processMessage(Message message) {
- super.processMessage(message);
switch (message.what) {
case CMD_START_DHCP:
if (mRegisteredForPreDhcpNotification) {
@@ -578,10 +593,9 @@
}
}
- class DhcpState extends LoggingState {
+ class DhcpState extends State {
@Override
public void enter() {
- super.enter();
clearDhcpState();
if (initInterface() && initSockets()) {
mReceiveThread = new ReceiveThread();
@@ -679,7 +693,9 @@
}
}
+ @Override
public void exit() {
+ super.exit();
mKickAlarm.cancel();
mTimeoutAlarm.cancel();
}
@@ -784,15 +800,9 @@
}
}
- class DhcpHaveLeaseState extends LoggingState {
- @Override
- public void enter() {
- super.enter();
- }
-
+ class DhcpHaveLeaseState extends State {
@Override
public boolean processMessage(Message message) {
- super.processMessage(message);
switch (message.what) {
case CMD_EXPIRE_DHCP:
Log.d(TAG, "Lease expired!");
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index af78839..815133a 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -26,14 +26,23 @@
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpManager;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.RaEvent;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.os.ConditionVariable;
+import android.os.Parcelable;
import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -43,6 +52,7 @@
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
+import java.util.List;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -56,9 +66,12 @@
public class ApfTest extends AndroidTestCase {
private static final int TIMEOUT_MS = 500;
+ @Mock IpConnectivityLog mLog;
+
@Override
public void setUp() throws Exception {
super.setUp();
+ MockitoAnnotations.initMocks(this);
// Load up native shared library containing APF interpreter exposed via JNI.
System.loadLibrary("servicestestsjni");
}
@@ -70,6 +83,9 @@
// least the minimum packet size.
private final static int MIN_PKT_SIZE = 15;
+ private final static boolean DROP_MULTICAST = true;
+ private final static boolean ALLOW_MULTICAST = false;
+
private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
assertEquals(expected, apfSimulate(program, packet, filterAge));
}
@@ -562,10 +578,10 @@
public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
private FileDescriptor mWriteSocket;
- public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter) throws
- Exception {
+ public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
+ IpConnectivityLog log) throws Exception {
super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
- ipManagerCallback, multicastFilter);
+ ipManagerCallback, multicastFilter, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -667,7 +683,7 @@
@LargeTest
public void testApfFilterIPv4() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
@@ -699,7 +715,7 @@
@LargeTest
public void testApfFilterIPv6() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -726,7 +742,7 @@
@LargeTest
public void testApfFilterMulticast() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Construct IPv4 and IPv6 multicast packets.
@@ -772,7 +788,7 @@
// Verify it can be initialized to on
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
+ apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
program = ipManagerCallback.getApfProgram();
assertDrop(program, bcastv4packet.array(), 0);
assertDrop(program, mcastv4packet.array(), 0);
@@ -804,7 +820,7 @@
@LargeTest
public void testApfFilterArp() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify initially ARP filter is off
@@ -867,6 +883,35 @@
verifyRaLifetime(ipManagerCallback, packet, lifetime);
}
+ private void verifyRaEvent(RaEvent expected) {
+ ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class);
+ verify(mLog, atLeastOnce()).log(captor.capture());
+ RaEvent got = lastRaEvent(captor.getAllValues());
+ if (!raEventEquals(expected, got)) {
+ assertEquals(expected, got); // fail for printing an assertion error message.
+ }
+ }
+
+ private RaEvent lastRaEvent(List<Parcelable> events) {
+ RaEvent got = null;
+ for (Parcelable ev : events) {
+ if (ev instanceof RaEvent) {
+ got = (RaEvent) ev;
+ }
+ }
+ return got;
+ }
+
+ private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
+ return (ev1 != null) && (ev2 != null)
+ && (ev1.routerLifetime == ev2.routerLifetime)
+ && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
+ && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
+ && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
+ && (ev1.rdnssLifetime == ev2.rdnssLifetime)
+ && (ev1.dnsslLifetime == ev2.dnsslLifetime);
+ }
+
private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
ByteBuffer packet) throws IOException, ErrnoException {
ipManagerCallback.resetApfProgramWait();
@@ -877,7 +922,7 @@
@LargeTest
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
+ TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify RA is passed the first time
@@ -891,6 +936,7 @@
assertPass(program, basePacket.array(), 0);
testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
+ verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
// Ensure zero-length options cause the packet to be silently skipped.
// Do this before we test other packets. http://b/29586253
@@ -916,6 +962,7 @@
prefixOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
+ verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -926,6 +973,7 @@
rdnssOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
+ verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -936,6 +984,7 @@
routeInfoOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
+ verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -948,6 +997,7 @@
// Note that lifetime of 2000 will be ignored in favor of shorter
// route lifetime of 1000.
testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
+ verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
// Verify that current program filters all five RAs:
verifyRaLifetime(ipManagerCallback, basePacket, 1000);