Snap for 11976889 from ff4e5a46c9e715c702120df4a6c5e9624c88b219 to mainline-art-release Change-Id: I0a61016d56777986438b0a0eab3a70d60934c007
diff --git a/src/android/net/apf/AndroidPacketFilter.java b/src/android/net/apf/AndroidPacketFilter.java index 2a7165b..8c7ff05 100644 --- a/src/android/net/apf/AndroidPacketFilter.java +++ b/src/android/net/apf/AndroidPacketFilter.java
@@ -44,9 +44,9 @@ void setMulticastFilter(boolean isEnabled); /** - * Set the APF data snapshot. + * Set the APF data snapshot and return the latest counter snapshot as a String. */ - void setDataSnapshot(byte[] data); + String setDataSnapshot(byte[] data); /** * Add TCP keepalive ack packet filter.
diff --git a/src/android/net/apf/ApfCounterTracker.java b/src/android/net/apf/ApfCounterTracker.java index e35f011..e86aab1 100644 --- a/src/android/net/apf/ApfCounterTracker.java +++ b/src/android/net/apf/ApfCounterTracker.java
@@ -64,6 +64,7 @@ PASSED_IPV6_ICMP, PASSED_IPV6_NON_ICMP, PASSED_IPV6_NS_MULTIPLE_OPTIONS, + PASSED_IPV6_NS_NO_ADDRESS, PASSED_IPV6_UNICAST_NON_ICMP, PASSED_NON_IP_UNICAST, PASSED_MDNS, @@ -81,7 +82,6 @@ DROPPED_IPV6_MULTICAST_PING, DROPPED_IPV6_NON_ICMP_MULTICAST, DROPPED_IPV6_NS_INVALID, - DROPPED_IPV6_NS_NO_ADDRESS, DROPPED_IPV6_NS_OTHER_HOST, DROPPED_802_3_FRAME, DROPPED_ETHERTYPE_NOT_ALLOWED,
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java index c705928..3aee15e 100644 --- a/src/android/net/apf/ApfFilter.java +++ b/src/android/net/apf/ApfFilter.java
@@ -36,7 +36,9 @@ import static android.net.apf.ApfConstants.ETH_TYPE_MAX; import static android.net.apf.ApfConstants.ETH_TYPE_MIN; import static android.net.apf.ApfConstants.FIXED_ARP_REPLY_HEADER; +import static android.net.apf.ApfConstants.ICMP6_CHECKSUM_OFFSET; import static android.net.apf.ApfConstants.ICMP6_CODE_OFFSET; +import static android.net.apf.ApfConstants.ICMP6_NS_OPTION_TYPE_OFFSET; import static android.net.apf.ApfConstants.ICMP6_NS_TARGET_IP_OFFSET; import static android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET; import static android.net.apf.ApfConstants.IPPROTO_HOPOPTS; @@ -55,17 +57,17 @@ import static android.net.apf.ApfConstants.IPV6_HEADER_LEN; import static android.net.apf.ApfConstants.IPV6_HOP_LIMIT_OFFSET; import static android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET; -import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX; import static android.net.apf.ApfConstants.IPV6_PAYLOAD_LEN_OFFSET; +import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX; import static android.net.apf.ApfConstants.IPV6_SRC_ADDR_OFFSET; import static android.net.apf.ApfConstants.MDNS_PORT; import static android.net.apf.ApfConstants.TCP_HEADER_SIZE_OFFSET; import static android.net.apf.ApfConstants.TCP_UDP_DESTINATION_PORT_OFFSET; import static android.net.apf.ApfConstants.TCP_UDP_SOURCE_PORT_OFFSET; import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID; -import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_NO_ADDRESS; import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST; import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_MULTIPLE_OPTIONS; +import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS; import static android.net.apf.BaseApfGenerator.MemorySlot; import static android.net.apf.BaseApfGenerator.Register.R0; import static android.net.apf.BaseApfGenerator.Register.R1; @@ -86,8 +88,12 @@ import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; +import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA_LEN; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; @@ -184,6 +190,7 @@ public boolean shouldHandleLightDoze; public long minMetricsSessionDurationMs; public boolean hasClatInterface; + public boolean shouldHandleArpOffload; } /** A wrapper class of {@link SystemClock} to be mocked in unit tests. */ @@ -281,6 +288,7 @@ // and PIO valid lifetimes. private final int mAcceptRaMinLft; private final boolean mShouldHandleLightDoze; + private final boolean mShouldHandleArpOffload; private final NetworkQuirkMetrics mNetworkQuirkMetrics; private final IpClientRaInfoMetrics mIpClientRaInfoMetrics; @@ -384,6 +392,7 @@ mMinRdnssLifetimeSec = config.minRdnssLifetimeSec; mAcceptRaMinLft = config.acceptRaMinLft; mShouldHandleLightDoze = config.shouldHandleLightDoze; + mShouldHandleArpOffload = config.shouldHandleArpOffload; mDependencies = dependencies; mNetworkQuirkMetrics = networkQuirkMetrics; mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics(); @@ -514,11 +523,13 @@ } } - public synchronized void setDataSnapshot(byte[] data) { + @Override + public synchronized String setDataSnapshot(byte[] data) { mDataSnapshot = data; if (mIsRunning) { mApfCounterTracker.updateCountersFromData(data); } + return mApfCounterTracker.getCounters().toString(); } private void log(String s) { @@ -1625,7 +1636,7 @@ Counter.DROPPED_ARP_OTHER_HOST); ApfV6Generator v6Gen = tryToConvertToApfV6Generator(gen); - if (v6Gen != null) { + if (v6Gen != null && mShouldHandleArpOffload) { // Ethernet requires that all packets be at least 60 bytes long v6Gen.addAllocate(60) .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) @@ -1829,6 +1840,54 @@ return addresses; } + /** + * Generate allocate and transmit code to send ICMPv6 non-DAD NA packets. + */ + @GuardedBy("this") + private void generateNonDadNaTransmitLocked(ApfV6GeneratorBase<?> gen) + throws IllegalInstructionException { + final int ipv6PayloadLen = ICMPV6_NA_HEADER_LEN + ICMPV6_ND_OPTION_TLLA_LEN; + final int pktLen = ETH_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLen; + + gen.addAllocate(pktLen); + + // Ethernet Header + gen.addPacketCopy(ICMP6_NS_OPTION_TYPE_OFFSET + 2, ETHER_ADDR_LEN) // dst MAC address + .addDataCopy(mHardwareAddress) // src MAC address + .addWriteU16(ETH_P_IPV6); // IPv6 type + + int tclass = mDependencies.getNdTrafficClass(mInterfaceParams.name); + int vtf = (0x60000000 | (tclass << 20)); + // IPv6 header + gen.addWrite32(vtf) // IPv6 Header: version, traffic class, flowlabel + // payload length (2 bytes) | next header: ICMPv6 (1 byte) | hop limit (1 byte) + .addWrite32((ipv6PayloadLen << 16) | ((IPPROTO_ICMPV6 << 8) | 255)) + // target ip is guaranteed to be non-tentative as we already check before + // we call transmit, but the link local ip can potentially be tentative. + .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // src ip + .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN); // dst ip + + // ICMPv6 header and payload + // ICMPv6 type: NA (1 byte) | code: 0 (1 byte) | checksum: set to payload size (2 bytes) + gen.addWrite32((ICMPV6_NEIGHBOR_ADVERTISEMENT << 24) | ipv6PayloadLen) + // Always set Router flag to prevent host deleting routes point at the router + // Always set Override flag to update neighbor's cache + // Solicited flag set to 1 if non DAD, refer to RFC4861#7.2.4 + .addWrite32(0xe0000000) // flags: R=1, S=1, O=1 + .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // target address + // lla option: type (1 byte) | lla option: length (1 byte) + .addWriteU16((ICMPV6_ND_OPTION_TLLA << 8) | 1) + .addDataCopy(mHardwareAddress); // lla option: link layer address + + gen.addTransmitL4( + ETHER_HEADER_LEN, // ip_ofs + ICMP6_CHECKSUM_OFFSET, // csum_ofs + IPV6_SRC_ADDR_OFFSET, // csum_start + IPPROTO_ICMPV6, // partial_sum + false // udp + ); + } + @GuardedBy("this") private void generateNsFilterLocked(ApfV6Generator v6Gen) throws IllegalInstructionException { @@ -1837,8 +1896,9 @@ true /* includeTentative */, true /* includeAnycast */); if (allIPv6Addrs.isEmpty()) { - // There is no IPv6 link local address. - v6Gen.addCountAndDrop(DROPPED_IPV6_NS_NO_ADDRESS); + // If there is no IPv6 link local address, allow all NS packets to avoid racing + // against RS. + v6Gen.addCountAndPass(PASSED_IPV6_NS_NO_ADDRESS); return; } @@ -1912,7 +1972,7 @@ // pass // (APFv6+ specific logic) if it's ICMPv6 NS: // if there are no IPv6 addresses (including link local address) on the interface: - // drop + // pass // if MAC dst is none of known {unicast, multicast, broadcast} MAC addresses // drop // if IPv6 dst prefix is "ff02::1:ff00:0/104" but is none of solicited-node multicast
diff --git a/src/android/net/apf/ApfV4Generator.java b/src/android/net/apf/ApfV4Generator.java index 5b19d35..a41f033 100644 --- a/src/android/net/apf/ApfV4Generator.java +++ b/src/android/net/apf/ApfV4Generator.java
@@ -202,6 +202,20 @@ } @Override + public ApfV4Generator addCountAndDropIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException { + final String tgt = getUniqueLabel(); + return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndDrop(cnt).defineLabel(tgt); + } + + @Override + public ApfV4Generator addCountAndPassIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException { + final String tgt = getUniqueLabel(); + return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndPass(cnt).defineLabel(tgt); + } + + @Override public ApfV4Generator addCountAndPassIfR0IsOneOf(@NonNull Set<Long> values, ApfCounterTracker.Counter cnt) throws IllegalInstructionException { if (values.isEmpty()) {
diff --git a/src/android/net/apf/ApfV4GeneratorBase.java b/src/android/net/apf/ApfV4GeneratorBase.java index 860a21a..ced1d68 100644 --- a/src/android/net/apf/ApfV4GeneratorBase.java +++ b/src/android/net/apf/ApfV4GeneratorBase.java
@@ -500,6 +500,22 @@ ApfCounterTracker.Counter cnt) throws IllegalInstructionException; /** + * Add instructions to the end of the program to increase counter and drop packet if the + * bytes of the packet at an offset specified by register0 match {@code bytes}. + * WARNING: may modify R1 + */ + public abstract Type addCountAndDropIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException; + + /** + * Add instructions to the end of the program to increase counter and pass packet if the + * bytes of the packet at an offset specified by register0 match {@code bytes}. + * WARNING: may modify R1 + */ + public abstract Type addCountAndPassIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException; + + /** * Add instructions to the end of the program to increase counter and pass packet if the * value in register0 is one of {@code values}. * WARNING: may modify R1
diff --git a/src/android/net/apf/ApfV6GeneratorBase.java b/src/android/net/apf/ApfV6GeneratorBase.java index 6ec4eda..a9abed6 100644 --- a/src/android/net/apf/ApfV6GeneratorBase.java +++ b/src/android/net/apf/ApfV6GeneratorBase.java
@@ -712,6 +712,20 @@ } @Override + public final Type addCountAndDropIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException { + final String tgt = getUniqueLabel(); + return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndDrop(cnt).defineLabel(tgt); + } + + @Override + public final Type addCountAndPassIfBytesAtR0Equal(byte[] bytes, + ApfCounterTracker.Counter cnt) throws IllegalInstructionException { + final String tgt = getUniqueLabel(); + return addJumpIfBytesAtR0NotEqual(bytes, tgt).addCountAndPass(cnt).defineLabel(tgt); + } + + @Override public Type addCountAndPassIfR0IsOneOf(@NonNull Set<Long> values, ApfCounterTracker.Counter cnt) throws IllegalInstructionException { if (values.isEmpty()) {
diff --git a/src/android/net/apf/LegacyApfFilter.java b/src/android/net/apf/LegacyApfFilter.java index 99aab80..e4f709b 100644 --- a/src/android/net/apf/LegacyApfFilter.java +++ b/src/android/net/apf/LegacyApfFilter.java
@@ -435,11 +435,13 @@ mDependencies.onThreadCreated(mReceiveThread); } - public synchronized void setDataSnapshot(byte[] data) { + @Override + public synchronized String setDataSnapshot(byte[] data) { mDataSnapshot = data; if (mIsRunning) { mApfCounterTracker.updateCountersFromData(data); } + return mApfCounterTracker.getCounters().toString(); } private void log(String s) {
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 304b038..deaabac 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java
@@ -46,6 +46,7 @@ import static com.android.net.module.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID; import static com.android.networkstack.apishim.ConstantsShim.IFA_F_MANAGETEMPADDR; import static com.android.networkstack.apishim.ConstantsShim.IFA_F_NOPREFIXROUTE; +import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_ARP_OFFLOAD_FORCE_DISABLE; import static com.android.networkstack.util.NetworkStackUtils.APF_HANDLE_LIGHT_DOZE_FORCE_DISABLE; import static com.android.networkstack.util.NetworkStackUtils.APF_NEW_RA_FILTER_VERSION; import static com.android.networkstack.util.NetworkStackUtils.APF_POLLING_COUNTERS_VERSION; @@ -199,15 +200,19 @@ public class IpClient extends StateMachine { private static final String TAG = IpClient.class.getSimpleName(); private static final boolean DBG = false; + private final boolean mApfDebug; // For message logging. private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class }; private static final SparseArray<String> sWhatToString = MessageUtils.findMessageNames(sMessageClasses); - // Two static concurrent hashmaps of interface name to logging classes. - // One holds StateMachine logs and the other connectivity packet logs. + // Static concurrent hashmaps of interface name to logging classes. + // This map holds StateMachine logs. private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>(); + // This map holds connectivity packet logs. private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>(); + // This map holds Apf logs. + private static final ConcurrentHashMap<String, SharedLog> sApfLogs = new ConcurrentHashMap<>(); private final NetworkStackIpMemoryStore mIpMemoryStore; private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance(); private final IpProvisioningMetrics mIpProvisioningMetrics = new IpProvisioningMetrics(); @@ -225,6 +230,12 @@ writer.println(String.format("--- BEGIN %s ---", ifname)); + final SharedLog apfLog = sApfLogs.get(ifname); + if (apfLog != null) { + writer.println("APF log:"); + apfLog.dump(null, writer, null); + } + final SharedLog smLog = sSmLogs.get(ifname); if (smLog != null) { writer.println("State machine log:"); @@ -266,16 +277,24 @@ public static class IpClientCallbacksWrapper { private static final String PREFIX = "INVOKE "; private final IIpClientCallbacks mCallback; + @NonNull private final SharedLog mLog; @NonNull + private final SharedLog mApfLog; + @NonNull private final NetworkInformationShim mShim; + private final boolean mApfDebug; + @VisibleForTesting - protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log, - @NonNull NetworkInformationShim shim) { + protected IpClientCallbacksWrapper(IIpClientCallbacks callback, @NonNull SharedLog log, + @NonNull SharedLog apfLog, @NonNull NetworkInformationShim shim, + boolean apfDebug) { mCallback = callback; mLog = log; + mApfLog = apfLog; mShim = shim; + mApfDebug = apfDebug; } private void log(String msg) { @@ -396,6 +415,9 @@ public boolean installPacketFilter(byte[] filter) { log("installPacketFilter(byte[" + filter.length + "])"); try { + if (mApfDebug) { + mApfLog.log("updated APF program: " + HexDump.toHexString(filter)); + } mCallback.installPacketFilter(filter); } catch (RemoteException e) { log("Failed to call installPacketFilter", e); @@ -682,6 +704,7 @@ private final WakeupMessage mProvisioningTimeoutAlarm; private final WakeupMessage mDhcpActionTimeoutAlarm; private final SharedLog mLog; + private final SharedLog mApfLog; private final LocalLog mConnectivityPacketLog; private final MessageHandlingLogger mMsgStateLogger; private final IpConnectivityLog mMetricsLog; @@ -711,6 +734,7 @@ private final boolean mApfShouldHandleLightDoze; private final boolean mEnableApfPollingCounters; private final boolean mPopulateLinkAddressLifetime; + private final boolean mApfShouldHandleArpOffload; private InterfaceParams mInterfaceParams; @@ -929,8 +953,11 @@ mLog = sSmLogs.get(mInterfaceName); sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS)); mConnectivityPacketLog = sPktLogs.get(mInterfaceName); + sApfLogs.putIfAbsent(mInterfaceName, new SharedLog(10 /* maxRecords */, mTag)); + mApfLog = sApfLogs.get(mInterfaceName); + mApfDebug = Log.isLoggable(ApfFilter.class.getSimpleName(), Log.DEBUG); mMsgStateLogger = new MessageHandlingLogger(); - mCallback = new IpClientCallbacksWrapper(callback, mLog, mShim); + mCallback = new IpClientCallbacksWrapper(callback, mLog, mApfLog, mShim, mApfDebug); // TODO: Consider creating, constructing, and passing in some kind of // InterfaceController.Dependencies class. @@ -957,6 +984,8 @@ // Light doze mode status checking API is only available at T or later releases. mApfShouldHandleLightDoze = SdkLevel.isAtLeastT() && mDependencies.isFeatureNotChickenedOut( mContext, APF_HANDLE_LIGHT_DOZE_FORCE_DISABLE); + mApfShouldHandleArpOffload = mDependencies.isFeatureNotChickenedOut( + mContext, APF_HANDLE_ARP_OFFLOAD_FORCE_DISABLE); mPopulateLinkAddressLifetime = mDependencies.isFeatureEnabled(context, IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION); @@ -1370,7 +1399,9 @@ } } apfFilter.dump(pw); - + pw.println("APF log:"); + pw.println("mApfDebug: " + mApfDebug); + mApfLog.dump(fd, pw, args); } else { pw.print("No active ApfFilter; "); if (provisioningConfig == null) { @@ -2563,6 +2594,7 @@ apfConfig.acceptRaMinLft = 0; } apfConfig.shouldHandleLightDoze = mApfShouldHandleLightDoze; + apfConfig.shouldHandleArpOffload = mApfShouldHandleArpOffload; apfConfig.minMetricsSessionDurationMs = mApfCounterPollingIntervalMs; apfConfig.hasClatInterface = mHasSeenClatInterface; return mDependencies.maybeCreateApfFilter(mContext, apfConfig, mInterfaceParams, @@ -3337,7 +3369,8 @@ case EVENT_READ_PACKET_FILTER_COMPLETE: { if (mApfFilter != null) { - mApfFilter.setDataSnapshot((byte[]) msg.obj); + String snapShotStr = mApfFilter.setDataSnapshot((byte[]) msg.obj); + mLog.log("readPacketFilterComplete, ApfCounters: " + snapShotStr); } mApfDataSnapshotComplete.open(); break;
diff --git a/src/com/android/networkstack/metrics/IpProvisioningMetrics.java b/src/com/android/networkstack/metrics/IpProvisioningMetrics.java index 5ca996e..daaf207 100644 --- a/src/com/android/networkstack/metrics/IpProvisioningMetrics.java +++ b/src/com/android/networkstack/metrics/IpProvisioningMetrics.java
@@ -16,11 +16,14 @@ package com.android.networkstack.metrics; +import static android.stats.connectivity.Ipv6ProvisioningMode.IPV6_PROV_MODE_UNKNOWN; + import android.net.util.Stopwatch; import android.stats.connectivity.DhcpErrorCode; import android.stats.connectivity.DhcpFeature; import android.stats.connectivity.DisconnectCode; import android.stats.connectivity.HostnameTransResult; +import android.stats.connectivity.Ipv6ProvisioningMode; import com.android.net.module.util.ConnectivityUtils; @@ -147,6 +150,15 @@ } /** + * Write the IPv6 provisioning mode proto into mStatsBuilder. This API should be called only + * once during the provisioning lifetime cycle. + */ + public void setIpv6ProvisioningMode(final Ipv6ProvisioningMode mode) { + if (mode == IPV6_PROV_MODE_UNKNOWN || mStatsBuilder.hasIpv6ProvisioningMode()) return; + mStatsBuilder.setIpv6ProvisioningMode(mode); + } + + /** * Write the NetworkIpProvisioningReported proto into statsd. */ public NetworkIpProvisioningReported statsWrite() { @@ -166,7 +178,8 @@ stats.getProvisioningDurationMicros(), stats.getDisconnectCode().getNumber(), DhcpSession, - stats.getRandomNumber()); + stats.getRandomNumber(), + stats.getIpv6ProvisioningMode().getNumber()); mWatch.reset(); return stats; }
diff --git a/src/com/android/networkstack/metrics/stats.proto b/src/com/android/networkstack/metrics/stats.proto index 06419f9..43bc414 100644 --- a/src/com/android/networkstack/metrics/stats.proto +++ b/src/com/android/networkstack/metrics/stats.proto
@@ -107,6 +107,9 @@ // The random number between 0 ~ 999 for sampling optional int32 random_number = 7; + + // Check which IPv6 provisioning mode is used for current connection + optional .android.stats.connectivity.Ipv6ProvisioningMode ipv6_provisioning_mode = 8; } /**
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java index 5446119..ac2832b 100755 --- a/src/com/android/networkstack/util/NetworkStackUtils.java +++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -300,6 +300,12 @@ public static final String IGNORE_TCP_INFO_FOR_BLOCKED_UIDS = "ignore_tcp_info_for_blocked_uids"; + /** + * Kill switch flag to disable the feature of handle arp offload in Apf. + */ + public static final String APF_HANDLE_ARP_OFFLOAD_FORCE_DISABLE = + "apf_handle_arp_offload_force_disable"; + static { System.loadLibrary("networkstackutilsjni"); }
diff --git a/tests/unit/src/android/net/apf/ApfNewTest.kt b/tests/unit/src/android/net/apf/ApfNewTest.kt index d271b2e..6863fb9 100644 --- a/tests/unit/src/android/net/apf/ApfNewTest.kt +++ b/tests/unit/src/android/net/apf/ApfNewTest.kt
@@ -28,14 +28,15 @@ import android.net.apf.ApfCounterTracker.Counter.DROPPED_ETH_BROADCAST import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID -import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_NO_ADDRESS import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST import android.net.apf.ApfCounterTracker.Counter.PASSED_ALLOCATE_FAILURE import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP +import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_REQUEST import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_FROM_DHCPV4_SERVER import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_ICMP import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_MULTIPLE_OPTIONS +import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS import android.net.apf.ApfCounterTracker.Counter.PASSED_TRANSMIT_FAILURE import android.net.apf.ApfCounterTracker.Counter.TOTAL_PACKETS import android.net.apf.ApfFilter.Dependencies @@ -375,6 +376,12 @@ gen.addCountAndDropIfBytesAtR0NotEqual(byteArrayOf(1), PASSED_ARP) } assertFailsWith<IllegalArgumentException> { + gen.addCountAndDropIfBytesAtR0Equal(byteArrayOf(1), PASSED_ARP) + } + assertFailsWith<IllegalArgumentException> { + gen.addCountAndPassIfBytesAtR0Equal(byteArrayOf(1), DROPPED_ETH_BROADCAST) + } + assertFailsWith<IllegalArgumentException> { gen.addCountAndDropIfR0AnyBitsSet(3, PASSED_ARP) } assertFailsWith<IllegalArgumentException> { @@ -448,6 +455,12 @@ v4gen.addCountAndPassIfR0NotEquals(3, DROPPED_ETH_BROADCAST) } assertFailsWith<IllegalArgumentException> { + v4gen.addCountAndDropIfBytesAtR0Equal(byteArrayOf(1), PASSED_ARP) + } + assertFailsWith<IllegalArgumentException> { + v4gen.addCountAndPassIfBytesAtR0Equal(byteArrayOf(1), DROPPED_ETH_BROADCAST) + } + assertFailsWith<IllegalArgumentException> { v4gen.addCountAndDropIfR0LessThan(3, PASSED_ARP) } assertFailsWith<IllegalArgumentException> { @@ -1302,6 +1315,30 @@ .addCountTrampoline() .generate() verifyProgramRun(APF_VERSION_6, program, testPacket, PASSED_ARP, incTotal = incTotal) + + program = getGenerator() + .addLoadImmediate(R0, 1) + .addCountAndDropIfBytesAtR0Equal( + byteArrayOf(2, 3), DROPPED_ETH_BROADCAST) + .addPass() + .addCountTrampoline() + .generate() + verifyProgramRun( + APF_VERSION_6, + program, + testPacket, + DROPPED_ETH_BROADCAST, + incTotal = incTotal + ) + + program = getGenerator() + .addLoadImmediate(R0, 1) + .addCountAndPassIfBytesAtR0Equal( + byteArrayOf(2, 3), PASSED_ARP) + .addPass() + .addCountTrampoline() + .generate() + verifyProgramRun(APF_VERSION_6, program, testPacket, PASSED_ARP, incTotal = incTotal) } private fun doTestEtherTypeAllowListFilter(apfVersion: Int) { @@ -1880,6 +1917,41 @@ } @Test + fun testArpOffloadDisabled() { + val apfConfig = getDefaultConfig() + apfConfig.shouldHandleArpOffload = false + val apfFilter = + ApfFilter( + context, + apfConfig, + ifParams, + ipClientCallback, + metrics, + dependencies + ) + verify(ipClientCallback, times(2)).installPacketFilter(any()) + val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) + val lp = LinkProperties() + lp.addLinkAddress(linkAddress) + apfFilter.setLinkProperties(lp) + val programCaptor = ArgumentCaptor.forClass(ByteArray::class.java) + verify(ipClientCallback, times(3)).installPacketFilter(programCaptor.capture()) + val program = programCaptor.value + val receivedArpPacketBuf = ArpPacket.buildArpPacket( + arpBroadcastMacAddress, + senderMacAddress, + hostIpv4Address, + HexDump.hexStringToByteArray("000000000000"), + senderIpv4Address, + ARP_REQUEST.toShort() + ) + val receivedArpPacket = ByteArray(ARP_ETHER_IPV4_LEN) + receivedArpPacketBuf.get(receivedArpPacket) + verifyProgramRun(APF_VERSION_6, program, receivedArpPacket, PASSED_ARP_REQUEST) + apfFilter.shutdown() + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) fun testNsFilterNoIPv6() { `when`(dependencies.getAnycast6Addresses(any())).thenReturn(listOf()) @@ -1905,12 +1977,12 @@ val nsPkt = "01020304050600010203040586DD6000000000183AFF200100000000000" + "00200001A1122334420010000000000000200001A334411228700452900" + "00000020010000000000000200001A33441122" - // when there is no IPv6 addresses -> drop NS packet + // when there is no IPv6 addresses -> pass NS packet verifyProgramRun( APF_VERSION_6, program, HexDump.hexStringToByteArray(nsPkt), - DROPPED_IPV6_NS_NO_ADDRESS + PASSED_IPV6_NS_NO_ADDRESS ) apfFilter.shutdown() @@ -2296,6 +2368,7 @@ config.multicastFilter = false config.ieee802_3Filter = false config.ethTypeBlackList = IntArray(0) + config.shouldHandleArpOffload = true return config } }
diff --git a/tests/unit/src/android/net/apf/ApfTestUtils.java b/tests/unit/src/android/net/apf/ApfTestUtils.java index d1f2a23..0b3ea65 100644 --- a/tests/unit/src/android/net/apf/ApfTestUtils.java +++ b/tests/unit/src/android/net/apf/ApfTestUtils.java
@@ -247,13 +247,13 @@ private boolean mInstallPacketFilterReturn = true; MockIpClientCallback() { - super(mock(IIpClientCallbacks.class), mock(SharedLog.class), - NetworkInformationShimImpl.newInstance()); + super(mock(IIpClientCallbacks.class), mock(SharedLog.class), mock(SharedLog.class), + NetworkInformationShimImpl.newInstance(), false); } MockIpClientCallback(boolean installPacketFilterReturn) { - super(mock(IIpClientCallbacks.class), mock(SharedLog.class), - NetworkInformationShimImpl.newInstance()); + super(mock(IIpClientCallbacks.class), mock(SharedLog.class), mock(SharedLog.class), + NetworkInformationShimImpl.newInstance(), false); mInstallPacketFilterReturn = installPacketFilterReturn; }
diff --git a/tests/unit/src/com/android/networkstack/metrics/NetworkIpProvisioningMetricsTest.java b/tests/unit/src/com/android/networkstack/metrics/NetworkIpProvisioningMetricsTest.java index 01d94e2..4479e9a 100644 --- a/tests/unit/src/com/android/networkstack/metrics/NetworkIpProvisioningMetricsTest.java +++ b/tests/unit/src/com/android/networkstack/metrics/NetworkIpProvisioningMetricsTest.java
@@ -16,15 +16,17 @@ package com.android.networkstack.metrics; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import android.net.dhcp.DhcpPacket; import android.net.metrics.DhcpErrorEvent; import android.stats.connectivity.DhcpErrorCode; import android.stats.connectivity.DhcpFeature; import android.stats.connectivity.DisconnectCode; import android.stats.connectivity.HostnameTransResult; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import android.stats.connectivity.Ipv6ProvisioningMode; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -86,6 +88,7 @@ // The maximum number of DHCP error code counts is MAX_DHCP_ERROR_COUNT assertEquals(mMetrics.MAX_DHCP_ERROR_COUNT, mStats.getDhcpSession().getErrorCodeCount()); } + @Test public void testIpProvisioningMetrics_CollectMetrics() throws Exception { final NetworkIpProvisioningReported mStats; @@ -158,4 +161,24 @@ assertTrue(mStats.getProvisioningDurationMicros() >= 1000); } } + + @Test + public void testIpProvisioningMetrics_setIpv6ProvisioningMode() throws Exception { + final IpProvisioningMetrics metrics = new IpProvisioningMetrics(); + metrics.reset(); + + metrics.setIpv6ProvisioningMode(Ipv6ProvisioningMode.IPV6_PROV_MODE_SLAAC); + metrics.setIPv6ProvisionedLatencyOnFirstTime(true); + metrics.setDisconnectCode(DisconnectCode.DC_NORMAL_TERMINATION); + + // don't allow to override the previous metircs. + metrics.setIpv6ProvisioningMode(Ipv6ProvisioningMode.IPV6_PROV_MODE_DHCP6_PD_HEURISTIC); + + final NetworkIpProvisioningReported stats = metrics.statsWrite(); + + assertTrue(stats.getIpv4LatencyMicros() == 0); + assertTrue(stats.getIpv6LatencyMicros() > 0); + assertEquals(Ipv6ProvisioningMode.IPV6_PROV_MODE_SLAAC, stats.getIpv6ProvisioningMode()); + assertEquals(DisconnectCode.DC_NORMAL_TERMINATION, stats.getDisconnectCode()); + } }