Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a689b530 authored by Xiao Ma's avatar Xiao Ma
Browse files

Log NUD failure metrics upon neighbor losts due to MAC address changes.

When the probed neighbor is default gateway, checking if the MAC address
has changed is required. If MAC address does change, log the NUD metrics
while triggering the neighbor lost callback.

Bug: 162944199
Test: atest NetworkStackTests
Change-Id: I8315b11b75c83be2a58c9891589f2e582083bbda
parent 26886241
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -408,6 +408,7 @@ public class IpReachabilityMonitor {
                    + " to: " + event.macAddr;
            mLog.w(logMsg);
            mCallback.notifyLost(event.ip, logMsg);
            logNudFailed(event, NudEventType.NUD_MAC_ADDRESS_CHANGED);
            return;
        }
        maybeRestoreNeighborParameters();
@@ -446,6 +447,8 @@ public class IpReachabilityMonitor {
        final boolean lostProvisioning =
                (mLinkProperties.isIpv4Provisioned() && !whatIfLp.isIpv4Provisioned())
                || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned());
        final NudEventType type = getNudFailureEventType(isFromProbe(),
                isProbedNudFailureDueToRoam(), lostProvisioning);

        if (lostProvisioning) {
            final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
@@ -454,7 +457,7 @@ public class IpReachabilityMonitor {
            // an InetAddress argument.
            mCallback.notifyLost(ip, logMsg);
        }
        logNudFailed(event, lostProvisioning);
        logNudFailed(event, type);
    }

    private void maybeRestoreNeighborParameters() {
@@ -595,10 +598,17 @@ public class IpReachabilityMonitor {
        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
    }

    private void logNudFailed(final NeighborEvent event, boolean lostProvisioning) {
    private void logNudFailed(final NeighborEvent event, final NudEventType type) {
        // The legacy metrics only record whether the failure came from a probe and whether
        // the network is still provisioned. They do not record provisioning failures due to
        // multicast resolicits finding that the MAC address has changed.
        final boolean lostProvisioning =
                ((type == NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL)
                || (type == NudEventType.NUD_CONFIRM_FAILED_CRITICAL)
                || (type == NudEventType.NUD_ORGANIC_FAILED_CRITICAL));
        final int eventType = nudFailureEventType(isFromProbe(), lostProvisioning);
        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
        logNeighborLostEvent(event, lostProvisioning);
        logNeighborLostEvent(event, type);
    }

    /**
@@ -637,12 +647,11 @@ public class IpReachabilityMonitor {
     * Log NUD failure metrics with new Westworld APIs while the function using mMetricsLog API
     * still sends the legacy metrics, @see #logNudFailed.
     */
    private void logNeighborLostEvent(final NeighborEvent event, boolean isProvisioningLost) {
    private void logNeighborLostEvent(final NeighborEvent event, final NudEventType type) {
        final IpType ipType = (event.ip instanceof Inet6Address) ? IpType.IPV6 : IpType.IPV4;
        mIpReachabilityMetrics.setNudIpType(ipType);
        mIpReachabilityMetrics.setNudNeighborType(getNeighborType(event));
        mIpReachabilityMetrics.setNudEventType(getNudFailureEventType(isFromProbe(),
                isProbedNudFailureDueToRoam(), isProvisioningLost));
        mIpReachabilityMetrics.setNudEventType(type);
        mIpReachabilityMetrics.statsWrite();
    }

+38 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.net.LinkProperties
import android.net.RouteInfo
import android.net.metrics.IpConnectivityLog
import android.net.util.InterfaceParams
import android.net.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION
import android.net.util.SharedLog
import android.os.Handler
import android.os.HandlerThread
@@ -36,6 +37,7 @@ import android.stats.connectivity.IpType.IPV6
import android.stats.connectivity.NudEventType
import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED
import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED_CRITICAL
import android.stats.connectivity.NudEventType.NUD_MAC_ADDRESS_CHANGED
import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED
import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED
@@ -50,6 +52,7 @@ import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.networkstack.metrics.IpReachabilityMonitorMetrics
import com.android.net.module.util.netlink.StructNdMsg.NUD_FAILED
import com.android.net.module.util.netlink.StructNdMsg.NUD_REACHABLE
import com.android.net.module.util.netlink.StructNdMsg.NUD_STALE
import com.android.testutils.makeNewNeighMessage
import com.android.testutils.waitForIdle
@@ -59,7 +62,9 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyObject
import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.doAnswer
@@ -324,6 +329,29 @@ class IpReachabilityMonitorTest {
        verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
    }

    private fun runNeighborReachableButMacAddrChangedTest(
        newLp: LinkProperties,
        neighbor: InetAddress,
        ipType: IpType
    ) {
        doReturn(true).`when`(dependencies).isFeatureEnabled(anyObject(),
                eq(IP_REACHABILITY_MCAST_RESOLICIT_VERSION), anyBoolean())

        reachabilityMonitor.updateLinkProperties(newLp)

        neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
                "001122334455" /* oldMac */))
        handlerThread.waitForIdle(TEST_TIMEOUT_MS)
        verify(callback, never()).notifyLost(eq(neighbor), anyString())

        reachabilityMonitor.probeAll(true /* dueToRoam */)

        neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
                "1122334455aa" /* newMac */))
        verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(neighbor), anyString())
        verifyNudFailureMetrics(NUD_MAC_ADDRESS_CHANGED, ipType, NUD_NEIGHBOR_GATEWAY)
    }

    @Test
    fun testLoseProvisioning_Ipv4DnsLost() {
        runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS)
@@ -519,4 +547,14 @@ class IpReachabilityMonitorTest {

        verifyNudFailureMetrics(NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
    }

    @Test
    fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChanged() {
        runNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY, IPV6)
    }

    @Test
    fun testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChanged() {
        runNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY, IPV4)
    }
}