Record events for RA option lifetimes
This patch defines a new android.net.metrics.RaEvent class carrying lifetime values contained in RA packets. RaEvent are recorded when ApfFilter processes a new RA for which there is no match. Example: ConnectivityMetricsEvent(15:39:39.808, 0, 0): RaEvent(lifetimes: router=3600s, prefix_valid=2592000s, prefix_preferred=604800s, route_info=-1s, dnssl=-1s, rdnss=3600s) Change-Id: Ia28652e03ed442d5f2a686ef5b3fafbcb77c503a
This commit is contained in:
@@ -26153,6 +26153,18 @@ package android.net.metrics {
|
||||
field public final int netId;
|
||||
}
|
||||
|
||||
public final class RaEvent implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.net.metrics.RaEvent> CREATOR;
|
||||
field public final long dnsslLifetime;
|
||||
field public final long prefixPreferredLifetime;
|
||||
field public final long prefixValidLifetime;
|
||||
field public final long rdnssLifetime;
|
||||
field public final long routeInfoLifetime;
|
||||
field public final long routerLifetime;
|
||||
}
|
||||
|
||||
public final class ValidationProbeEvent implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public static void logEvent(int, long, int, int);
|
||||
|
||||
95
core/java/android/net/metrics/RaEvent.java
Normal file
95
core/java/android/net/metrics/RaEvent.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.metrics;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* An event logged when the APF packet socket receives an RA packet.
|
||||
* {@hide}
|
||||
*/
|
||||
@SystemApi
|
||||
public final class RaEvent implements Parcelable {
|
||||
|
||||
// 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;
|
||||
public final long prefixValidLifetime;
|
||||
public final long prefixPreferredLifetime;
|
||||
public final long routeInfoLifetime;
|
||||
public final long rdnssLifetime;
|
||||
public final long dnsslLifetime;
|
||||
|
||||
/** {@hide} */
|
||||
public RaEvent(long routerLifetime, long prefixValidLifetime, long prefixPreferredLifetime,
|
||||
long routeInfoLifetime, long rdnssLifetime, long dnsslLifetime) {
|
||||
this.routerLifetime = routerLifetime;
|
||||
this.prefixValidLifetime = prefixValidLifetime;
|
||||
this.prefixPreferredLifetime = prefixPreferredLifetime;
|
||||
this.routeInfoLifetime = routeInfoLifetime;
|
||||
this.rdnssLifetime = rdnssLifetime;
|
||||
this.dnsslLifetime = dnsslLifetime;
|
||||
}
|
||||
|
||||
private RaEvent(Parcel in) {
|
||||
routerLifetime = in.readLong();
|
||||
prefixValidLifetime = in.readLong();
|
||||
prefixPreferredLifetime = in.readLong();
|
||||
routeInfoLifetime = in.readLong();
|
||||
rdnssLifetime = in.readLong();
|
||||
dnsslLifetime = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeLong(routerLifetime);
|
||||
out.writeLong(prefixValidLifetime);
|
||||
out.writeLong(prefixPreferredLifetime);
|
||||
out.writeLong(routeInfoLifetime);
|
||||
out.writeLong(rdnssLifetime);
|
||||
out.writeLong(dnsslLifetime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("RaEvent(lifetimes: ")
|
||||
.append(String.format("router=%ds, ", routerLifetime))
|
||||
.append(String.format("prefix_valid=%ds, ", prefixValidLifetime))
|
||||
.append(String.format("prefix_preferred=%ds, ", prefixPreferredLifetime))
|
||||
.append(String.format("route_info=%ds, ", routeInfoLifetime))
|
||||
.append(String.format("rdnss=%ds, ", rdnssLifetime))
|
||||
.append(String.format("dnssl=%ds)", dnsslLifetime))
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<RaEvent> CREATOR = new Parcelable.Creator<RaEvent>() {
|
||||
public RaEvent createFromParcel(Parcel in) {
|
||||
return new RaEvent(in);
|
||||
}
|
||||
|
||||
public RaEvent[] newArray(int size) {
|
||||
return new RaEvent[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.net.ip.IpManager;
|
||||
import android.net.metrics.ApfProgramEvent;
|
||||
import android.net.metrics.ApfStats;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.metrics.RaEvent;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.PacketSocketAddress;
|
||||
@@ -357,7 +358,7 @@ public class ApfFilter {
|
||||
}
|
||||
|
||||
// Can't be static because it's in a non-static inner class.
|
||||
// TODO: Make this final once RA is its own class.
|
||||
// TODO: Make this static once RA is its own class.
|
||||
private int uint8(byte b) {
|
||||
return b & 0xff;
|
||||
}
|
||||
@@ -366,8 +367,8 @@ public class ApfFilter {
|
||||
return s & 0xffff;
|
||||
}
|
||||
|
||||
private long uint32(int s) {
|
||||
return s & 0xffffffff;
|
||||
private long uint32(int i) {
|
||||
return i & 0xffffffffL;
|
||||
}
|
||||
|
||||
private void prefixOptionToString(StringBuffer sb, int offset) {
|
||||
@@ -427,6 +428,11 @@ public class ApfFilter {
|
||||
return lifetimeOffset + lifetimeLength;
|
||||
}
|
||||
|
||||
private int addNonLifetimeU32(int lastNonLifetimeStart) {
|
||||
return addNonLifetime(lastNonLifetimeStart,
|
||||
ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
|
||||
}
|
||||
|
||||
// Note that this parses RA and may throw IllegalArgumentException (from
|
||||
// Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
|
||||
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
|
||||
@@ -446,11 +452,20 @@ public class ApfFilter {
|
||||
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;
|
||||
|
||||
// Ensures that the RA is not truncated.
|
||||
mPacket.position(ICMP6_RA_OPTION_OFFSET);
|
||||
while (mPacket.hasRemaining()) {
|
||||
int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
|
||||
int optionLength = (((int)mPacket.get(mPacket.position() + 1)) & 0xff) * 8;
|
||||
final int position = mPacket.position();
|
||||
final int optionType = uint8(mPacket.get(position));
|
||||
final int optionLength = uint8(mPacket.get(position + 1)) * 8;
|
||||
switch (optionType) {
|
||||
case ICMP6_PREFIX_OPTION_TYPE:
|
||||
// Parse valid lifetime
|
||||
@@ -461,19 +476,29 @@ public class ApfFilter {
|
||||
lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
|
||||
ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
|
||||
ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
|
||||
mPrefixOptionOffsets.add(mPacket.position());
|
||||
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, so process
|
||||
// together:
|
||||
// These three options have the same lifetime offset and size, and
|
||||
// are processed with the same specialized addNonLifetime4B:
|
||||
case ICMP6_RDNSS_OPTION_TYPE:
|
||||
mRdnssOptionOffsets.add(mPacket.position());
|
||||
// Fall through.
|
||||
mRdnssOptionOffsets.add(position);
|
||||
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
|
||||
rdnssLifetime =
|
||||
uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
|
||||
break;
|
||||
case ICMP6_ROUTE_INFO_OPTION_TYPE:
|
||||
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
|
||||
routeInfoLifetime =
|
||||
uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
|
||||
break;
|
||||
case ICMP6_DNSSL_OPTION_TYPE:
|
||||
// Parse lifetime
|
||||
lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
|
||||
ICMP6_4_BYTE_LIFETIME_OFFSET,
|
||||
ICMP6_4_BYTE_LIFETIME_LEN);
|
||||
lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
|
||||
dnsslLifetime =
|
||||
uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position));
|
||||
break;
|
||||
default:
|
||||
// RFC4861 section 4.2 dictates we ignore unknown options for fowards
|
||||
@@ -484,11 +509,14 @@ public class ApfFilter {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Invalid option length opt=%d len=%d", optionType, optionLength));
|
||||
}
|
||||
mPacket.position(mPacket.position() + optionLength);
|
||||
mPacket.position(position + optionLength);
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Ignoring lifetimes (which may change) does {@code packet} match this RA?
|
||||
@@ -517,16 +545,19 @@ public class ApfFilter {
|
||||
continue;
|
||||
}
|
||||
|
||||
int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
|
||||
long val;
|
||||
final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
|
||||
final long optionLifetime;
|
||||
switch (lifetimeLength) {
|
||||
case 2: val = byteBuffer.getShort(offset); break;
|
||||
case 4: val = byteBuffer.getInt(offset); break;
|
||||
default: throw new IllegalStateException("bogus lifetime size " + length);
|
||||
case 2:
|
||||
optionLifetime = uint16(byteBuffer.getShort(offset));
|
||||
break;
|
||||
case 4:
|
||||
optionLifetime = uint32(byteBuffer.getInt(offset));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
|
||||
}
|
||||
// Mask to size, converting signed to unsigned
|
||||
val &= (1L << (lifetimeLength * 8)) - 1;
|
||||
minLifetime = Math.min(minLifetime, val);
|
||||
minLifetime = Math.min(minLifetime, optionLifetime);
|
||||
}
|
||||
return minLifetime;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user