• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 // ktlint does not allow annotating function argument literals inline. Disable the specific rule
17 // since this negatively affects readability.
18 @file:Suppress("ktlint:standard:comment-wrapping")
19 
20 package android.net.ip
21 
22 import android.annotation.SuppressLint
23 import android.content.Context
24 import android.net.INetd
25 import android.net.InetAddresses.parseNumericAddress
26 import android.net.IpPrefix
27 import android.net.LinkAddress
28 import android.net.LinkProperties
29 import android.net.RouteInfo
30 import android.net.metrics.IpConnectivityLog
31 import android.os.Handler
32 import android.os.HandlerThread
33 import android.os.MessageQueue
34 import android.os.MessageQueue.OnFileDescriptorEventListener
35 import android.stats.connectivity.IpType
36 import android.stats.connectivity.IpType.IPV4
37 import android.stats.connectivity.IpType.IPV6
38 import android.stats.connectivity.NudEventType
39 import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED
40 import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED_CRITICAL
41 import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED
42 import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED_CRITICAL
43 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED
44 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
45 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED
46 import android.stats.connectivity.NudNeighborType
47 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_BOTH
48 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_DNS
49 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_GATEWAY
50 import android.system.ErrnoException
51 import android.system.OsConstants.EAGAIN
52 import androidx.test.filters.SmallTest
53 import androidx.test.runner.AndroidJUnit4
54 import com.android.net.module.util.InterfaceParams
55 import com.android.net.module.util.SharedLog
56 import com.android.net.module.util.ip.IpNeighborMonitor
57 import com.android.net.module.util.netlink.StructNdMsg.NUD_FAILED
58 import com.android.net.module.util.netlink.StructNdMsg.NUD_PROBE
59 import com.android.net.module.util.netlink.StructNdMsg.NUD_REACHABLE
60 import com.android.net.module.util.netlink.StructNdMsg.NUD_STALE
61 import com.android.networkstack.metrics.IpReachabilityMonitorMetrics
62 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION
63 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION
64 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION
65 import com.android.testutils.makeNewNeighMessage
66 import com.android.testutils.waitForIdle
67 import java.io.FileDescriptor
68 import java.lang.annotation.ElementType
69 import java.lang.annotation.Repeatable
70 import java.lang.annotation.Retention
71 import java.lang.annotation.RetentionPolicy
72 import java.lang.annotation.Target
73 import java.net.Inet4Address
74 import java.net.Inet6Address
75 import java.net.InetAddress
76 import java.util.concurrent.CompletableFuture
77 import java.util.concurrent.ConcurrentLinkedQueue
78 import java.util.concurrent.TimeUnit
79 import kotlin.test.assertFalse
80 import kotlin.test.assertTrue
81 import kotlin.test.fail
82 import org.junit.After
83 import org.junit.Before
84 import org.junit.Rule
85 import org.junit.Test
86 import org.junit.rules.TestName
87 import org.junit.runner.RunWith
88 import org.mockito.ArgumentCaptor
89 import org.mockito.ArgumentMatchers.any
90 import org.mockito.ArgumentMatchers.anyInt
91 import org.mockito.ArgumentMatchers.anyString
92 import org.mockito.ArgumentMatchers.eq
93 import org.mockito.Mockito.doAnswer
94 import org.mockito.Mockito.doReturn
95 import org.mockito.Mockito.mock
96 import org.mockito.Mockito.never
97 import org.mockito.Mockito.timeout
98 import org.mockito.Mockito.verify
99 
100 private const val TEST_TIMEOUT_MS = 10_000L
101 
102 private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
103 private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
104 
105 private val TEST_MAC_1 = "001122334455"
106 private val TEST_MAC_2 = "1122334455aa"
107 
108 // IPv4 gateway is also DNS server.
109 private val TEST_IPV4_GATEWAY_DNS = parseNumericAddress("192.168.222.100") as Inet4Address
110 
111 private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
112 private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
113 
114 private val TEST_IPV6_LINKLOCAL_LINKADDR = LinkAddress("fe80::123/64")
115 private val TEST_IPV6_LINKLOCAL_GATEWAY = parseNumericAddress("fe80::1") as Inet6Address
116 private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY = parseNumericAddress("fe80::1%21") as Inet6Address
117 private val TEST_IPV6_LINKLOCAL_GATEWAY2 = parseNumericAddress("fe80::2") as Inet6Address
118 private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY2 = parseNumericAddress("fe80::2%22") as Inet6Address
119 
120 // DNSes inside IP prefix
121 private val TEST_IPV4_DNS = parseNumericAddress("192.168.222.1") as Inet4Address
122 private val TEST_IPV6_DNS = parseNumericAddress("2001:db8::321") as Inet6Address
123 private val TEST_IPV6_DNS2 = parseNumericAddress("2001:db8::456") as Inet6Address
124 
125 private val TEST_IFACE = InterfaceParams("fake0", 21, null)
126 
127 @SuppressLint("NewApi")
128 private val TEST_LINK_PROPERTIES = LinkProperties().apply {
129     interfaceName = TEST_IFACE.name
130     addLinkAddress(TEST_IPV4_LINKADDR)
131     addLinkAddress(TEST_IPV6_LINKADDR)
132 
133     // Add on link routes
134     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
135     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
136 
137     // Add default routes
138     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
139     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
140 
141     addDnsServer(TEST_IPV4_DNS)
142     addDnsServer(TEST_IPV6_DNS)
143 }
144 
145 @SuppressLint("NewApi")
<lambda>null146 private val TEST_IPV4_ONLY_LINK_PROPERTIES = LinkProperties().apply {
147     interfaceName = TEST_IFACE.name
148     addLinkAddress(TEST_IPV4_LINKADDR)
149 
150     // Add on link routes
151     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
152 
153     // Add default routes
154     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY_DNS))
155 
156     addDnsServer(TEST_IPV4_GATEWAY_DNS)
157 }
158 
159 @SuppressLint("NewApi")
<lambda>null160 private val TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES = LinkProperties().apply {
161     interfaceName = TEST_IFACE.name
162     addLinkAddress(TEST_IPV6_LINKADDR)
163     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
164 
165     // Add on link routes
166     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
167     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
168 
169     // Add default routes
170     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
171 
172     addDnsServer(TEST_IPV6_DNS)
173 }
174 
175 @SuppressLint("NewApi")
<lambda>null176 private val TEST_DUAL_LINK_PROPERTIES = LinkProperties().apply {
177     interfaceName = TEST_IFACE.name
178     addLinkAddress(TEST_IPV4_LINKADDR)
179     addLinkAddress(TEST_IPV6_LINKADDR)
180     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
181 
182     // Add on link routes
183     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
184     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
185     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
186 
187     // Add default routes
188     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
189     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
190 
191     addDnsServer(TEST_IPV4_DNS)
192     addDnsServer(TEST_IPV6_DNS)
193     addDnsServer(TEST_IPV6_DNS2)
194 }
195 
196 /**
197  * Tests for IpReachabilityMonitor.
198  */
199 @RunWith(AndroidJUnit4::class)
200 @SmallTest
201 class IpReachabilityMonitorTest {
202     @get:Rule val mTestName = TestName()
203     private val callback = mock(IpReachabilityMonitor.Callback::class.java)
204     private val dependencies = mock(IpReachabilityMonitor.Dependencies::class.java)
205     private val log = mock(SharedLog::class.java)
206     private val context = mock(Context::class.java)
207     private val netd = mock(INetd::class.java)
208     private val fd = mock(FileDescriptor::class.java)
209     private val metricsLog = mock(IpConnectivityLog::class.java)
210     private val mIpReachabilityMonitorMetrics = mock(IpReachabilityMonitorMetrics::class.java)
211 
212     private val handlerThread = HandlerThread(IpReachabilityMonitorTest::class.simpleName)
<lambda>null213     private val handler by lazy { Handler(handlerThread.looper) }
214 
215     private lateinit var reachabilityMonitor: IpReachabilityMonitor
216     private lateinit var neighborMonitor: TestIpNeighborMonitor
217 
218     @Retention(RetentionPolicy.RUNTIME)
219     @Target(ElementType.METHOD)
220     @Repeatable(FlagArray::class)
221     annotation class Flag(val name: String, val enabled: Boolean)
222 
223     @Retention(RetentionPolicy.RUNTIME)
224     @Target(ElementType.METHOD)
225     annotation class FlagArray(val value: Array<Flag>)
226 
227     /**
228      * A version of [IpNeighborMonitor] that overrides packet reading from a socket, and instead
229      * allows the test to enqueue test packets via [enqueuePacket].
230      */
231     private class TestIpNeighborMonitor(
232         handler: Handler,
233         log: SharedLog,
234         cb: NeighborEventConsumer,
235         private val fd: FileDescriptor
236     ) : IpNeighborMonitor(handler, log, cb) {
237 
238         private val pendingPackets = ConcurrentLinkedQueue<ByteArray>()
239         val msgQueue = mock(MessageQueue::class.java)
240 
241         private var eventListener: OnFileDescriptorEventListener? = null
242 
createFdnull243         override fun createFd() = fd
244         override fun getMessageQueue() = msgQueue
245 
246         fun enqueuePacket(packet: ByteArray) {
247             val listener = eventListener ?: fail("IpNeighborMonitor was not yet started")
248             pendingPackets.add(packet)
249             handler.post {
250                 listener.onFileDescriptorEvents(fd, OnFileDescriptorEventListener.EVENT_INPUT)
251             }
252         }
253 
readPacketnull254         override fun readPacket(fd: FileDescriptor, packetBuffer: ByteArray): Int {
255             val packet = pendingPackets.poll() ?: throw ErrnoException("No pending packet", EAGAIN)
256             if (packet.size > packetBuffer.size) {
257                 fail("Buffer (${packetBuffer.size}) is too small for packet (${packet.size})")
258             }
259             System.arraycopy(packet, 0, packetBuffer, 0, packet.size)
260             return packet.size
261         }
262 
onStartnull263         override fun onStart() {
264             super.onStart()
265 
266             // Find the file descriptor listener that was registered on the instrumented queue
267             val captor = ArgumentCaptor.forClass(OnFileDescriptorEventListener::class.java)
268             verify(msgQueue).addOnFileDescriptorEventListener(
269                 eq(fd),
270                 anyInt(),
271                 captor.capture()
272             )
273             eventListener = captor.value
274         }
275     }
276 
277     @Before
setUpnull278     fun setUp() {
279         doReturn(log).`when`(log).forSubComponent(anyString())
280         doReturn(true).`when`(fd).valid()
281         handlerThread.start()
282 
283         doAnswer { inv ->
284             val handler = inv.getArgument<Handler>(0)
285             val log = inv.getArgument<SharedLog>(1)
286             val cb = inv.getArgument<IpNeighborMonitor.NeighborEventConsumer>(2)
287             neighborMonitor = TestIpNeighborMonitor(handler, log, cb, fd)
288             neighborMonitor
289         }.`when`(dependencies).makeIpNeighborMonitor(any(), any(), any())
290         doReturn(mIpReachabilityMonitorMetrics)
291                 .`when`(dependencies).getIpReachabilityMonitorMetrics()
292 
293         // Set flags based on test method annotations.
294         // Note: because dependencies is a mock, all features that are not specified in flag
295         // annotations are either disabled or chickened out.
296         var testMethod = this::class.java.getMethod(mTestName.methodName)
297         val flags = testMethod.getAnnotationsByType(Flag::class.java)
298         for (f in flags) {
299             doReturn(f.enabled).`when`(dependencies).isFeatureEnabled(any(), eq(f.name))
300             doReturn(f.enabled).`when`(dependencies).isFeatureNotChickenedOut(any(), eq(f.name))
301         }
302 
303         val monitorFuture = CompletableFuture<IpReachabilityMonitor>()
304         // IpReachabilityMonitor needs to be started from the handler thread
305         handler.post {
306             monitorFuture.complete(IpReachabilityMonitor(
307                     context,
308                     TEST_IFACE,
309                     handler,
310                     log,
311                     callback,
312                     false /* useMultinetworkPolicyTracker */,
313                     dependencies,
314                     metricsLog,
315                     netd))
316         }
317         reachabilityMonitor = monitorFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
318         assertTrue(
319             ::neighborMonitor.isInitialized,
320                 "IpReachabilityMonitor did not call makeIpNeighborMonitor"
321         )
322     }
323 
324     @After
tearDownnull325     fun tearDown() {
326         // Ensure the handler thread is not accessing the fd while changing its mock
327         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
328         doReturn(false).`when`(fd).valid()
329         handlerThread.quitSafely()
330     }
331 
332     @Test
testLoseProvisioning_FirstProbeIsFailednull333     fun testLoseProvisioning_FirstProbeIsFailed() {
334         reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES)
335 
336         // Make the IPv4 DNS as reachable first.
337         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
338         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
339 
340         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_FAILED))
341         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
342             anyString(),
343             eq(NUD_ORGANIC_FAILED_CRITICAL)
344         )
345     }
346 
347     // Given the flag which ignores the NUD failure from the neighbor that is never reachable
348     // before has been enabled by default, we have to make the neighbor as reachable first and
349     // simulate a NUD failure by making a new NUD_FAILED neighbor message. So change the param
350     // "everReachable" to true always.
runLoseProvisioningTestnull351     private fun runLoseProvisioningTest(
352         newLp: LinkProperties,
353         lostNeighbor: InetAddress,
354         eventType: NudEventType
355     ) {
356         runLoseProvisioningTest(
357                 newLp,
358                 lostNeighbor,
359                 eventType,
360                 true, /* everReachable */
361                 true /* expectedNotifyLost */
362         )
363     }
364 
runLoseProvisioningTestnull365     private fun runLoseProvisioningTest(
366         newLp: LinkProperties,
367         lostNeighbor: InetAddress,
368         eventType: NudEventType,
369         everReachable: Boolean,
370         expectedNotifyLost: Boolean
371     ) {
372         reachabilityMonitor.updateLinkProperties(newLp)
373 
374         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_STALE))
375         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_STALE))
376         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_STALE))
377         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_STALE))
378         neighborMonitor.enqueuePacket(
379             makeNewNeighMessage(TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_STALE)
380         )
381         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY_DNS, NUD_STALE))
382 
383         // Make all neighbors used in the test as reachable.
384         if (everReachable) {
385             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
386             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_REACHABLE))
387             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_REACHABLE))
388             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
389             neighborMonitor.enqueuePacket(
390                 makeNewNeighMessage(TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_REACHABLE)
391             )
392             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY_DNS, NUD_REACHABLE))
393         }
394 
395         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_PROBE))
396         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
397         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
398 
399         if (expectedNotifyLost) {
400             verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
401                 anyString(),
402                 eq(eventType)
403             )
404         } else {
405              verify(callback, never()).notifyLost(anyString(), any())
406         }
407     }
408 
verifyNudFailureMetricsnull409     private fun verifyNudFailureMetrics(
410         eventType: NudEventType,
411         ipType: IpType,
412         lostNeighborType: NudNeighborType
413     ) {
414         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS)).setNudIpType(eq(ipType))
415         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
416                 .setNudEventType(eq(eventType))
417         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
418                 .setNudNeighborType(eq(lostNeighborType))
419     }
420 
verifyNudFailureMetricsNotReportednull421     private fun verifyNudFailureMetricsNotReported(
422     ) {
423         verify(mIpReachabilityMonitorMetrics, never()).setNudIpType(any())
424         verify(mIpReachabilityMonitorMetrics, never()).setNudEventType(any())
425         verify(mIpReachabilityMonitorMetrics, never()).setNudNeighborType(any())
426     }
427 
428     // Verify if the notifyLost will be called when one neighbor has lost but it's still
429     // provisioned.
runLoseNeighborStillProvisionedTestnull430     private fun runLoseNeighborStillProvisionedTest(
431         newLp: LinkProperties,
432         lostNeighbor: InetAddress,
433         eventType: NudEventType,
434         ipType: IpType,
435         lostNeighborType: NudNeighborType
436     ) {
437         reachabilityMonitor.updateLinkProperties(newLp)
438 
439         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
440         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
441         verify(callback, never()).notifyLost(anyString(), any(NudEventType::class.java))
442         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
443     }
444 
prepareNeighborReachableButMacAddrChangedTestnull445     private fun prepareNeighborReachableButMacAddrChangedTest(
446         newLp: LinkProperties,
447         neighbor: InetAddress,
448         macaddr: String
449     ) {
450         reachabilityMonitor.updateLinkProperties(newLp)
451 
452         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, macaddr))
453         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
454         verify(callback, never()).notifyLost(
455             anyString(),
456             any(NudEventType::class.java)
457         )
458     }
459 
460     @Test
testLoseProvisioning_Ipv4DnsLostnull461     fun testLoseProvisioning_Ipv4DnsLost() {
462         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS, NUD_ORGANIC_FAILED_CRITICAL)
463     }
464 
465     @Test
testLoseProvisioning_Ipv6DnsLostnull466     fun testLoseProvisioning_Ipv6DnsLost() {
467         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS, NUD_ORGANIC_FAILED_CRITICAL)
468     }
469 
470     @Test
testLoseProvisioning_Ipv4GatewayLostnull471     fun testLoseProvisioning_Ipv4GatewayLost() {
472         runLoseProvisioningTest(
473             TEST_LINK_PROPERTIES,
474             TEST_IPV4_GATEWAY,
475             NUD_ORGANIC_FAILED_CRITICAL
476         )
477     }
478 
479     @Test
testLoseProvisioning_Ipv6GatewayLostnull480     fun testLoseProvisioning_Ipv6GatewayLost() {
481         runLoseProvisioningTest(
482             TEST_LINK_PROPERTIES,
483             TEST_IPV6_GATEWAY,
484             NUD_ORGANIC_FAILED_CRITICAL
485         )
486     }
487 
488     @Test
489     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv4DnsLostnull490     fun testLoseProvisioning_ignoreOrganicIpv4DnsLost() {
491         runLoseProvisioningTest(
492             TEST_LINK_PROPERTIES,
493             TEST_IPV4_DNS,
494             NUD_ORGANIC_FAILED_CRITICAL,
495             false /* everReachable */,
496             false /* expectedNotifyLost */
497         )
498     }
499 
500     @Test
501     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv6DnsLostnull502     fun testLoseProvisioning_ignoreOrganicIpv6DnsLost() {
503         runLoseProvisioningTest(
504             TEST_LINK_PROPERTIES,
505             TEST_IPV6_DNS,
506             NUD_ORGANIC_FAILED_CRITICAL,
507             false /* everReachable */,
508             false /* expectedNotifyLost */
509         )
510     }
511 
512     @Test
513     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv4GatewayLostnull514     fun testLoseProvisioning_ignoreOrganicIpv4GatewayLost() {
515         runLoseProvisioningTest(
516             TEST_LINK_PROPERTIES,
517             TEST_IPV4_GATEWAY,
518             NUD_ORGANIC_FAILED_CRITICAL,
519             false /* everReachable */,
520             false /* expectedNotifyLost */
521         )
522     }
523 
524     @Test
525     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv6GatewayLostnull526     fun testLoseProvisioning_ignoreOrganicIpv6GatewayLost() {
527         runLoseProvisioningTest(
528             TEST_LINK_PROPERTIES,
529             TEST_IPV6_GATEWAY,
530             NUD_ORGANIC_FAILED_CRITICAL,
531             false /* everReachable */,
532             false /* expectedNotifyLost */
533         )
534     }
535 
536     @Test
testLoseProvisioning_ignoreNeverReachableIpv6GatewayLostnull537     fun testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost() {
538         runLoseProvisioningTest(
539             TEST_LINK_PROPERTIES,
540             TEST_IPV6_GATEWAY,
541             NUD_ORGANIC_FAILED_CRITICAL,
542             false /* everReachable */,
543             false /* expectedNotifyLost */
544         )
545     }
546 
547     @Test
testLoseProvisioning_ignoreNeverReachableIpv6DnsLostnull548     fun testLoseProvisioning_ignoreNeverReachableIpv6DnsLost() {
549         runLoseProvisioningTest(
550             TEST_LINK_PROPERTIES,
551             TEST_IPV6_DNS,
552             NUD_ORGANIC_FAILED_CRITICAL,
553             false /* everReachable */,
554             false /* expectedNotifyLost */
555         )
556     }
557 
558     @Test
testLoseProvisioning_notIgnoreEverReachableIpv6GatewayLostnull559     fun testLoseProvisioning_notIgnoreEverReachableIpv6GatewayLost() {
560         runLoseProvisioningTest(
561             TEST_LINK_PROPERTIES,
562             TEST_IPV6_GATEWAY,
563             NUD_ORGANIC_FAILED_CRITICAL,
564             true /* everReachable */,
565             true /* expectedNotifyLost */
566         )
567     }
568 
569     @Test
testLoseProvisioning_notIgnoreEverReachableIpv6DnsLostnull570     fun testLoseProvisioning_notIgnoreEverReachableIpv6DnsLost() {
571         runLoseProvisioningTest(
572             TEST_LINK_PROPERTIES,
573             TEST_IPV6_DNS,
574             NUD_ORGANIC_FAILED_CRITICAL,
575             true /* everReachable */,
576             true /* expectedNotifyLost */
577         )
578     }
579 
580     @Test
testLoseProvisioning_ignoreNeverReachableIpv4DnsLostnull581     fun testLoseProvisioning_ignoreNeverReachableIpv4DnsLost() {
582         runLoseProvisioningTest(
583             TEST_LINK_PROPERTIES,
584             TEST_IPV4_DNS,
585             NUD_ORGANIC_FAILED_CRITICAL,
586             false /* everReachable */,
587             false /* expectedNotifyLost */
588         )
589     }
590 
591     @Test
testLoseProvisioning_notIgnoreEverReachableIpv4GatewayLostnull592     fun testLoseProvisioning_notIgnoreEverReachableIpv4GatewayLost() {
593         runLoseProvisioningTest(
594             TEST_LINK_PROPERTIES,
595             TEST_IPV4_GATEWAY,
596             NUD_ORGANIC_FAILED_CRITICAL,
597             true /* everReachable */,
598             true /* expectedNotifyLost */
599         )
600     }
601 
602     @Test
testLoseProvisioning_notIgnoreEverReachableIpv4DnsLostnull603     fun testLoseProvisioning_notIgnoreEverReachableIpv4DnsLost() {
604         runLoseProvisioningTest(
605             TEST_LINK_PROPERTIES,
606             TEST_IPV4_DNS,
607             NUD_ORGANIC_FAILED_CRITICAL,
608             true /* everReachable */,
609             true /* expectedNotifyLost */
610         )
611     }
612 
613     @Test
testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost_withTwoIPv6DnsServersnull614     fun testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost_withTwoIPv6DnsServers() {
615         reachabilityMonitor.updateLinkProperties(TEST_DUAL_LINK_PROPERTIES)
616 
617         // IPv6 default router is never reachable, but two DNS servers do.
618         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
619         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
620         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_REACHABLE))
621         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_REACHABLE))
622 
623         // Push a NUD_FAILED event to IPv6 default router, this event should not trigger
624         // onReachabilityFailure callback given it's never reachable.
625         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_PROBE))
626         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_FAILED))
627         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
628 
629         verify(callback, never()).notifyLost(anyString(), any())
630 
631         // Then another NUD_FAILED from one of DNS servers, this event should not trigger
632         // onReachabilityFailure callback either.
633         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_PROBE))
634         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_FAILED))
635         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
636 
637         verify(callback, never()).notifyLost(anyString(), any())
638 
639         // Then we lost all IPv6 DNS servers, onReachabilityFailure callback should be triggered.
640         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_PROBE))
641         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_FAILED))
642         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
643 
644         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
645             anyString(),
646             eq(NUD_ORGANIC_FAILED_CRITICAL)
647         )
648     }
649 
650     @Test
testLoseProvisioning_ignoreNeverReachableIpv6DnsLost_withTwoIPv6Routesnull651     fun testLoseProvisioning_ignoreNeverReachableIpv6DnsLost_withTwoIPv6Routes() {
652         val TEST_DUAL_IPV6_ROUTERS_LINK_PROPERTIES = LinkProperties().apply {
653             interfaceName = TEST_IFACE.name
654             addLinkAddress(TEST_IPV4_LINKADDR)
655             addLinkAddress(TEST_IPV6_LINKADDR)
656             addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
657 
658             // Add on link routes
659             addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
660             addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
661             addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
662 
663             // Add default routes: one IPv4 default route and two IPv6 default routes.
664             addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
665             addRoute(
666                 RouteInfo(
667                     IpPrefix(parseNumericAddress("::"), 0),
668                     TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY
669                 )
670             )
671             addRoute(
672                 RouteInfo(
673                     IpPrefix(parseNumericAddress("::"), 0),
674                     TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY2
675                 )
676             )
677 
678             addDnsServer(TEST_IPV4_DNS)
679             addDnsServer(TEST_IPV6_DNS)
680         }
681 
682         reachabilityMonitor.updateLinkProperties(TEST_DUAL_IPV6_ROUTERS_LINK_PROPERTIES)
683 
684         // IPv6 DNS is never reachable, but two default gateways do.
685         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
686         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
687         neighborMonitor.enqueuePacket(
688             makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_REACHABLE)
689         )
690         neighborMonitor.enqueuePacket(
691             makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_REACHABLE)
692         )
693 
694         // Push a NUD_FAILED event to IPv6 DNS server, this event should not trigger
695         // onReachabilityFailure callback given it's never reachable.
696         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_PROBE))
697         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_FAILED))
698         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
699 
700         verify(callback, never()).notifyLost(anyString(), any())
701 
702         // Then another NUD_FAILED from one of IPv6 gateways, this event should not trigger
703         // onReachabilityFailure callback either.
704         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_PROBE))
705         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_FAILED))
706         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
707 
708         verify(callback, never()).notifyLost(anyString(), any())
709 
710         // Then we lost all IPv6 gateways, onReachabilityFailure callback should be triggered.
711         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_PROBE))
712         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_FAILED))
713         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
714 
715         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
716             anyString(),
717             eq(NUD_ORGANIC_FAILED_CRITICAL)
718         )
719     }
720 
runNudProbeFailureMetricsTestnull721     private fun runNudProbeFailureMetricsTest(
722         lp: LinkProperties,
723         lostNeighbor: InetAddress,
724         eventType: NudEventType,
725         ipType: IpType,
726         lostNeighborType: NudNeighborType
727     ) {
728         runLoseProvisioningTest(lp, lostNeighbor, eventType)
729         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
730     }
731 
732     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostPostRoamingnull733     fun testNudProbeFailedMetrics_Ipv6GatewayLostPostRoaming() {
734         reachabilityMonitor.probeAll(true /* dueToRoam */)
735         runNudProbeFailureMetricsTest(
736             TEST_LINK_PROPERTIES,
737             TEST_IPV6_GATEWAY,
738             NUD_POST_ROAMING_FAILED_CRITICAL,
739             IPV6,
740             NUD_NEIGHBOR_GATEWAY
741         )
742     }
743 
744     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostPostRoamingnull745     fun testNudProbeFailedMetrics_Ipv4GatewayLostPostRoaming() {
746         reachabilityMonitor.probeAll(true /* dueToRoam */)
747         runNudProbeFailureMetricsTest(
748             TEST_LINK_PROPERTIES,
749             TEST_IPV4_GATEWAY,
750             NUD_POST_ROAMING_FAILED_CRITICAL,
751             IPV4,
752             NUD_NEIGHBOR_GATEWAY
753         )
754     }
755 
756     @Test
testNudProbeFailedMetrics_Ipv6DnsLostPostRoamingnull757     fun testNudProbeFailedMetrics_Ipv6DnsLostPostRoaming() {
758         reachabilityMonitor.probeAll(true /* dueToRoam */)
759         runNudProbeFailureMetricsTest(
760             TEST_LINK_PROPERTIES,
761             TEST_IPV6_DNS,
762             NUD_POST_ROAMING_FAILED_CRITICAL,
763             IPV6,
764             NUD_NEIGHBOR_DNS
765         )
766     }
767 
768     @Test
testNudProbeFailedMetrics_Ipv4DnsLostPostRoamingnull769     fun testNudProbeFailedMetrics_Ipv4DnsLostPostRoaming() {
770         reachabilityMonitor.probeAll(true /* dueToRoam */)
771         runNudProbeFailureMetricsTest(
772             TEST_LINK_PROPERTIES,
773             TEST_IPV4_DNS,
774             NUD_POST_ROAMING_FAILED_CRITICAL,
775             IPV4,
776             NUD_NEIGHBOR_DNS
777         )
778     }
779 
780     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoamingnull781     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoaming() {
782         reachabilityMonitor.probeAll(true /* dueToRoam */)
783         runNudProbeFailureMetricsTest(
784             TEST_IPV4_ONLY_LINK_PROPERTIES,
785             TEST_IPV4_GATEWAY_DNS,
786             NUD_POST_ROAMING_FAILED_CRITICAL,
787             IPV4,
788             NUD_NEIGHBOR_BOTH
789         )
790     }
791 
792     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoamingnull793     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoaming() {
794         reachabilityMonitor.probeAll(true /* dueToRoam */)
795         runNudProbeFailureMetricsTest(
796             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
797             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
798             NUD_POST_ROAMING_FAILED_CRITICAL,
799             IPV6,
800             NUD_NEIGHBOR_GATEWAY
801         )
802     }
803 
804     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirmnull805     fun testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirm() {
806         reachabilityMonitor.probeAll(false /* dueToRoam */)
807         runNudProbeFailureMetricsTest(
808             TEST_LINK_PROPERTIES,
809             TEST_IPV6_GATEWAY,
810             NUD_CONFIRM_FAILED_CRITICAL,
811             IPV6,
812             NUD_NEIGHBOR_GATEWAY
813         )
814     }
815 
816     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirmnull817     fun testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirm() {
818         reachabilityMonitor.probeAll(false /* dueToRoam */)
819         runNudProbeFailureMetricsTest(
820             TEST_LINK_PROPERTIES,
821             TEST_IPV4_GATEWAY,
822             NUD_CONFIRM_FAILED_CRITICAL,
823             IPV4,
824             NUD_NEIGHBOR_GATEWAY
825         )
826     }
827 
828     @Test
testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirmnull829     fun testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirm() {
830         reachabilityMonitor.probeAll(false /* dueToRoam */)
831         runNudProbeFailureMetricsTest(
832             TEST_LINK_PROPERTIES,
833             TEST_IPV6_DNS,
834             NUD_CONFIRM_FAILED_CRITICAL,
835             IPV6,
836             NUD_NEIGHBOR_DNS
837         )
838     }
839 
840     @Test
testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirmnull841     fun testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirm() {
842         reachabilityMonitor.probeAll(false /* dueToRoam */)
843         runNudProbeFailureMetricsTest(
844             TEST_LINK_PROPERTIES,
845             TEST_IPV4_DNS,
846             NUD_CONFIRM_FAILED_CRITICAL,
847             IPV4,
848             NUD_NEIGHBOR_DNS
849         )
850     }
851 
852     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirmnull853     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirm() {
854         reachabilityMonitor.probeAll(false /* dueToRoam */)
855         runNudProbeFailureMetricsTest(
856             TEST_IPV4_ONLY_LINK_PROPERTIES,
857             TEST_IPV4_GATEWAY_DNS,
858             NUD_CONFIRM_FAILED_CRITICAL,
859             IPV4,
860             NUD_NEIGHBOR_BOTH
861         )
862     }
863 
864     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirmnull865     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirm() {
866         reachabilityMonitor.probeAll(false /* dueToRoam */)
867         runNudProbeFailureMetricsTest(
868             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
869             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
870             NUD_CONFIRM_FAILED_CRITICAL,
871             IPV6,
872             NUD_NEIGHBOR_GATEWAY
873         )
874     }
875 
876     @Test
testNudProbeFailedMetrics_IPv6GatewayLostOrganicnull877     fun testNudProbeFailedMetrics_IPv6GatewayLostOrganic() {
878         runNudProbeFailureMetricsTest(
879             TEST_LINK_PROPERTIES,
880             TEST_IPV6_GATEWAY,
881             NUD_ORGANIC_FAILED_CRITICAL,
882             IPV6,
883             NUD_NEIGHBOR_GATEWAY
884         )
885     }
886 
887     @Test
testNudProbeFailedMetrics_IPv4GatewayLostOrganicnull888     fun testNudProbeFailedMetrics_IPv4GatewayLostOrganic() {
889         runNudProbeFailureMetricsTest(
890             TEST_LINK_PROPERTIES,
891             TEST_IPV4_GATEWAY,
892             NUD_ORGANIC_FAILED_CRITICAL,
893             IPV4,
894             NUD_NEIGHBOR_GATEWAY
895         )
896     }
897 
898     @Test
testNudProbeFailedMetrics_IPv6DnsLostOrganicnull899     fun testNudProbeFailedMetrics_IPv6DnsLostOrganic() {
900         runNudProbeFailureMetricsTest(
901             TEST_LINK_PROPERTIES,
902             TEST_IPV6_DNS,
903             NUD_ORGANIC_FAILED_CRITICAL,
904             IPV6,
905             NUD_NEIGHBOR_DNS
906         )
907     }
908 
909     @Test
testNudProbeFailedMetrics_IPv4DnsLostOrganicnull910     fun testNudProbeFailedMetrics_IPv4DnsLostOrganic() {
911         runNudProbeFailureMetricsTest(
912             TEST_LINK_PROPERTIES,
913             TEST_IPV4_DNS,
914             NUD_ORGANIC_FAILED_CRITICAL,
915             IPV4,
916             NUD_NEIGHBOR_DNS
917         )
918     }
919 
920     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganicnull921     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganic() {
922         runNudProbeFailureMetricsTest(
923             TEST_IPV4_ONLY_LINK_PROPERTIES,
924             TEST_IPV4_GATEWAY_DNS,
925             NUD_ORGANIC_FAILED_CRITICAL,
926             IPV4,
927             NUD_NEIGHBOR_BOTH
928         )
929     }
930 
931     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganicnull932     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganic() {
933         runNudProbeFailureMetricsTest(
934             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
935             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
936             NUD_ORGANIC_FAILED_CRITICAL,
937             IPV6,
938             NUD_NEIGHBOR_GATEWAY
939         )
940     }
941 
942     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoamingnull943     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoaming() {
944         reachabilityMonitor.probeAll(true /* dueToRoam */)
945         runLoseNeighborStillProvisionedTest(
946             TEST_DUAL_LINK_PROPERTIES,
947             TEST_IPV6_DNS,
948             NUD_POST_ROAMING_FAILED,
949             IPV6,
950             NUD_NEIGHBOR_DNS
951         )
952     }
953 
954     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirmnull955     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirm() {
956         reachabilityMonitor.probeAll(false /* dueToRoam */)
957         runLoseNeighborStillProvisionedTest(
958             TEST_DUAL_LINK_PROPERTIES,
959             TEST_IPV6_DNS,
960             NUD_CONFIRM_FAILED,
961             IPV6,
962             NUD_NEIGHBOR_DNS
963         )
964     }
965 
966     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganicnull967     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganic() {
968         runLoseNeighborStillProvisionedTest(
969             TEST_DUAL_LINK_PROPERTIES,
970             TEST_IPV6_DNS,
971             NUD_ORGANIC_FAILED,
972             IPV6,
973             NUD_NEIGHBOR_DNS
974         )
975     }
976 
977     @Test
testNudProbeFailedMetrics_multipleProbesFromRoamFirstnull978     fun testNudProbeFailedMetrics_multipleProbesFromRoamFirst() {
979         reachabilityMonitor.probeAll(true /* dueToRoam */)
980         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
981         Thread.sleep(2)
982         reachabilityMonitor.probeAll(false /* dueToRoam */)
983         runLoseProvisioningTest(
984             TEST_LINK_PROPERTIES,
985             TEST_IPV6_GATEWAY,
986             NUD_POST_ROAMING_FAILED_CRITICAL
987         )
988 
989         verifyNudFailureMetrics(NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
990     }
991 
992     @Test
testNudProbeFailedMetrics_multipleProbesFromConfirmFirstnull993     fun testNudProbeFailedMetrics_multipleProbesFromConfirmFirst() {
994         reachabilityMonitor.probeAll(false /* dueToRoam */)
995         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
996         Thread.sleep(2)
997         reachabilityMonitor.probeAll(true /* dueToRoam */)
998         runLoseProvisioningTest(
999             TEST_LINK_PROPERTIES,
1000             TEST_IPV6_GATEWAY,
1001             NUD_CONFIRM_FAILED_CRITICAL
1002         )
1003 
1004         verifyNudFailureMetrics(NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
1005     }
1006 
probeWithNeighborEventnull1007     private fun probeWithNeighborEvent(dueToRoam: Boolean, neighbor: InetAddress, macaddr: String) {
1008         reachabilityMonitor.probeAll(dueToRoam)
1009         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_PROBE, macaddr))
1010     }
1011 
verifyNudMacAddrChangednull1012     private fun verifyNudMacAddrChanged(
1013         neighbor: InetAddress,
1014         eventType: NudEventType,
1015         ipType: IpType
1016     ) {
1017         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, TEST_MAC_2))
1018         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
1019             anyString(),
1020             eq(eventType)
1021         )
1022         verifyNudFailureMetrics(eventType, ipType, NUD_NEIGHBOR_GATEWAY)
1023     }
1024 
verifyNudMacAddrChangeNotReportednull1025     private fun verifyNudMacAddrChangeNotReported(
1026         neighbor: InetAddress,
1027     ) {
1028         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, TEST_MAC_2))
1029         verify(callback, never()).notifyLost(anyString(), any())
1030         verifyNudFailureMetricsNotReported()
1031     }
1032 
1033     @Test
1034     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1035     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoamingnull1036     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoaming() {
1037         prepareNeighborReachableButMacAddrChangedTest(
1038             TEST_LINK_PROPERTIES,
1039             TEST_IPV6_GATEWAY,
1040             TEST_MAC_1
1041         )
1042         probeWithNeighborEvent(true /* dueToRoam */, TEST_IPV6_GATEWAY, TEST_MAC_1)
1043         verifyNudMacAddrChanged(TEST_IPV6_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV6)
1044     }
1045 
1046     @Test
1047     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1048     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoamingnull1049     fun testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoaming() {
1050         prepareNeighborReachableButMacAddrChangedTest(
1051             TEST_LINK_PROPERTIES,
1052             TEST_IPV4_GATEWAY,
1053             TEST_MAC_1
1054         )
1055 
1056         probeWithNeighborEvent(true /* dueToRoam */, TEST_IPV4_GATEWAY, TEST_MAC_1)
1057         verifyNudMacAddrChanged(TEST_IPV4_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV4)
1058     }
1059 
1060     @Test
1061     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1062     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirmnull1063     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirm() {
1064         prepareNeighborReachableButMacAddrChangedTest(
1065             TEST_LINK_PROPERTIES,
1066             TEST_IPV6_GATEWAY,
1067             TEST_MAC_1
1068         )
1069 
1070         reachabilityMonitor.probeAll(false /* dueToRoam */)
1071         verifyNudMacAddrChangeNotReported(TEST_IPV6_GATEWAY)
1072     }
1073 
1074     @Test
1075     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1076     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganicnull1077     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganic() {
1078         prepareNeighborReachableButMacAddrChangedTest(
1079             TEST_LINK_PROPERTIES,
1080             TEST_IPV6_GATEWAY,
1081             TEST_MAC_1
1082         )
1083 
1084         verifyNudMacAddrChangeNotReported(TEST_IPV6_GATEWAY)
1085     }
1086 
1087     @SuppressLint("NewApi")
1088     @Test
testIsOnLinknull1089     fun testIsOnLink() {
1090         val routes: List<RouteInfo> = listOf(
1091                 RouteInfo(
1092                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
1093                         null /* gateway */,
1094                         null /* iface */,
1095                         RouteInfo.RTN_THROW
1096                 ),
1097                 RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), null /* gateway */)
1098         )
1099 
1100         assertTrue(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
1101     }
1102 
1103     @SuppressLint("NewApi")
1104     @Test
testIsOnLink_withThrowRoutesnull1105     fun testIsOnLink_withThrowRoutes() {
1106         val routes: List<RouteInfo> = listOf(
1107                 RouteInfo(
1108                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
1109                         null /* gateway */,
1110                         null /* iface */,
1111                         RouteInfo.RTN_THROW
1112                 )
1113         )
1114 
1115         assertFalse(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
1116     }
1117 }
1118