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_NEVER_REACHABLE_NEIGHBOR_VERSION
63 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION
64 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION
65 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION
66 import com.android.testutils.makeNewNeighMessage
67 import com.android.testutils.waitForIdle
68 import java.io.FileDescriptor
69 import java.lang.annotation.ElementType
70 import java.lang.annotation.Repeatable
71 import java.lang.annotation.Retention
72 import java.lang.annotation.RetentionPolicy
73 import java.lang.annotation.Target
74 import java.net.Inet4Address
75 import java.net.Inet6Address
76 import java.net.InetAddress
77 import java.util.concurrent.CompletableFuture
78 import java.util.concurrent.ConcurrentLinkedQueue
79 import java.util.concurrent.TimeUnit
80 import kotlin.test.assertFalse
81 import kotlin.test.assertTrue
82 import kotlin.test.fail
83 import org.junit.After
84 import org.junit.Before
85 import org.junit.Rule
86 import org.junit.Test
87 import org.junit.rules.TestName
88 import org.junit.runner.RunWith
89 import org.mockito.ArgumentCaptor
90 import org.mockito.ArgumentMatchers.any
91 import org.mockito.ArgumentMatchers.anyInt
92 import org.mockito.ArgumentMatchers.anyString
93 import org.mockito.ArgumentMatchers.eq
94 import org.mockito.Mockito.doAnswer
95 import org.mockito.Mockito.doReturn
96 import org.mockito.Mockito.mock
97 import org.mockito.Mockito.never
98 import org.mockito.Mockito.timeout
99 import org.mockito.Mockito.verify
100 
101 private const val TEST_TIMEOUT_MS = 10_000L
102 
103 private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
104 private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
105 
106 private val TEST_MAC_1 = "001122334455"
107 private val TEST_MAC_2 = "1122334455aa"
108 
109 // IPv4 gateway is also DNS server.
110 private val TEST_IPV4_GATEWAY_DNS = parseNumericAddress("192.168.222.100") as Inet4Address
111 
112 private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
113 private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
114 
115 private val TEST_IPV6_LINKLOCAL_LINKADDR = LinkAddress("fe80::123/64")
116 private val TEST_IPV6_LINKLOCAL_GATEWAY = parseNumericAddress("fe80::1") as Inet6Address
117 private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY = parseNumericAddress("fe80::1%21") as Inet6Address
118 private val TEST_IPV6_LINKLOCAL_GATEWAY2 = parseNumericAddress("fe80::2") as Inet6Address
119 private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY2 = parseNumericAddress("fe80::2%22") as Inet6Address
120 
121 // DNSes inside IP prefix
122 private val TEST_IPV4_DNS = parseNumericAddress("192.168.222.1") as Inet4Address
123 private val TEST_IPV6_DNS = parseNumericAddress("2001:db8::321") as Inet6Address
124 private val TEST_IPV6_DNS2 = parseNumericAddress("2001:db8::456") as Inet6Address
125 
126 private val TEST_IFACE = InterfaceParams("fake0", 21, null)
127 
128 @SuppressLint("NewApi")
129 private val TEST_LINK_PROPERTIES = LinkProperties().apply {
130     interfaceName = TEST_IFACE.name
131     addLinkAddress(TEST_IPV4_LINKADDR)
132     addLinkAddress(TEST_IPV6_LINKADDR)
133 
134     // Add on link routes
135     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
136     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
137 
138     // Add default routes
139     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
140     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
141 
142     addDnsServer(TEST_IPV4_DNS)
143     addDnsServer(TEST_IPV6_DNS)
144 }
145 
146 @SuppressLint("NewApi")
<lambda>null147 private val TEST_IPV4_ONLY_LINK_PROPERTIES = LinkProperties().apply {
148     interfaceName = TEST_IFACE.name
149     addLinkAddress(TEST_IPV4_LINKADDR)
150 
151     // Add on link routes
152     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
153 
154     // Add default routes
155     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY_DNS))
156 
157     addDnsServer(TEST_IPV4_GATEWAY_DNS)
158 }
159 
160 @SuppressLint("NewApi")
<lambda>null161 private val TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES = LinkProperties().apply {
162     interfaceName = TEST_IFACE.name
163     addLinkAddress(TEST_IPV6_LINKADDR)
164     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
165 
166     // Add on link routes
167     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
168     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
169 
170     // Add default routes
171     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
172 
173     addDnsServer(TEST_IPV6_DNS)
174 }
175 
176 @SuppressLint("NewApi")
<lambda>null177 private val TEST_DUAL_LINK_PROPERTIES = LinkProperties().apply {
178     interfaceName = TEST_IFACE.name
179     addLinkAddress(TEST_IPV4_LINKADDR)
180     addLinkAddress(TEST_IPV6_LINKADDR)
181     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
182 
183     // Add on link routes
184     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
185     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
186     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
187 
188     // Add default routes
189     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
190     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
191 
192     addDnsServer(TEST_IPV4_DNS)
193     addDnsServer(TEST_IPV6_DNS)
194     addDnsServer(TEST_IPV6_DNS2)
195 }
196 
197 /**
198  * Tests for IpReachabilityMonitor.
199  */
200 @RunWith(AndroidJUnit4::class)
201 @SmallTest
202 class IpReachabilityMonitorTest {
203     @get:Rule val mTestName = TestName()
204     private val callback = mock(IpReachabilityMonitor.Callback::class.java)
205     private val dependencies = mock(IpReachabilityMonitor.Dependencies::class.java)
206     private val log = mock(SharedLog::class.java)
207     private val context = mock(Context::class.java)
208     private val netd = mock(INetd::class.java)
209     private val fd = mock(FileDescriptor::class.java)
210     private val metricsLog = mock(IpConnectivityLog::class.java)
211     private val mIpReachabilityMonitorMetrics = mock(IpReachabilityMonitorMetrics::class.java)
212 
213     private val handlerThread = HandlerThread(IpReachabilityMonitorTest::class.simpleName)
<lambda>null214     private val handler by lazy { Handler(handlerThread.looper) }
215 
216     private lateinit var reachabilityMonitor: IpReachabilityMonitor
217     private lateinit var neighborMonitor: TestIpNeighborMonitor
218 
219     @Retention(RetentionPolicy.RUNTIME)
220     @Target(ElementType.METHOD)
221     @Repeatable(FlagArray::class)
222     annotation class Flag(val name: String, val enabled: Boolean)
223 
224     @Retention(RetentionPolicy.RUNTIME)
225     @Target(ElementType.METHOD)
226     annotation class FlagArray(val value: Array<Flag>)
227 
228     /**
229      * A version of [IpNeighborMonitor] that overrides packet reading from a socket, and instead
230      * allows the test to enqueue test packets via [enqueuePacket].
231      */
232     private class TestIpNeighborMonitor(
233         handler: Handler,
234         log: SharedLog,
235         cb: NeighborEventConsumer,
236         private val fd: FileDescriptor
237     ) : IpNeighborMonitor(handler, log, cb) {
238 
239         private val pendingPackets = ConcurrentLinkedQueue<ByteArray>()
240         val msgQueue = mock(MessageQueue::class.java)
241 
242         private var eventListener: OnFileDescriptorEventListener? = null
243 
createFdnull244         override fun createFd() = fd
245         override fun getMessageQueue() = msgQueue
246 
247         fun enqueuePacket(packet: ByteArray) {
248             val listener = eventListener ?: fail("IpNeighborMonitor was not yet started")
249             pendingPackets.add(packet)
250             handler.post {
251                 listener.onFileDescriptorEvents(fd, OnFileDescriptorEventListener.EVENT_INPUT)
252             }
253         }
254 
readPacketnull255         override fun readPacket(fd: FileDescriptor, packetBuffer: ByteArray): Int {
256             val packet = pendingPackets.poll() ?: throw ErrnoException("No pending packet", EAGAIN)
257             if (packet.size > packetBuffer.size) {
258                 fail("Buffer (${packetBuffer.size}) is too small for packet (${packet.size})")
259             }
260             System.arraycopy(packet, 0, packetBuffer, 0, packet.size)
261             return packet.size
262         }
263 
onStartnull264         override fun onStart() {
265             super.onStart()
266 
267             // Find the file descriptor listener that was registered on the instrumented queue
268             val captor = ArgumentCaptor.forClass(OnFileDescriptorEventListener::class.java)
269             verify(msgQueue).addOnFileDescriptorEventListener(
270                 eq(fd),
271                 anyInt(),
272                 captor.capture()
273             )
274             eventListener = captor.value
275         }
276     }
277 
278     @Before
setUpnull279     fun setUp() {
280         doReturn(log).`when`(log).forSubComponent(anyString())
281         doReturn(true).`when`(fd).valid()
282         handlerThread.start()
283 
284         doAnswer { inv ->
285             val handler = inv.getArgument<Handler>(0)
286             val log = inv.getArgument<SharedLog>(1)
287             val cb = inv.getArgument<IpNeighborMonitor.NeighborEventConsumer>(2)
288             neighborMonitor = TestIpNeighborMonitor(handler, log, cb, fd)
289             neighborMonitor
290         }.`when`(dependencies).makeIpNeighborMonitor(any(), any(), any())
291         doReturn(mIpReachabilityMonitorMetrics)
292                 .`when`(dependencies).getIpReachabilityMonitorMetrics()
293 
294         // Set flags based on test method annotations.
295         // Note: because dependencies is a mock, all features that are not specified in flag
296         // annotations are either disabled or chickened out.
297         var testMethod = this::class.java.getMethod(mTestName.methodName)
298         val flags = testMethod.getAnnotationsByType(Flag::class.java)
299         for (f in flags) {
300             doReturn(f.enabled).`when`(dependencies).isFeatureEnabled(any(), eq(f.name))
301             doReturn(f.enabled).`when`(dependencies).isFeatureNotChickenedOut(any(), eq(f.name))
302         }
303 
304         val monitorFuture = CompletableFuture<IpReachabilityMonitor>()
305         // IpReachabilityMonitor needs to be started from the handler thread
306         handler.post {
307             monitorFuture.complete(IpReachabilityMonitor(
308                     context,
309                     TEST_IFACE,
310                     handler,
311                     log,
312                     callback,
313                     false /* useMultinetworkPolicyTracker */,
314                     dependencies,
315                     metricsLog,
316                     netd))
317         }
318         reachabilityMonitor = monitorFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
319         assertTrue(
320             ::neighborMonitor.isInitialized,
321                 "IpReachabilityMonitor did not call makeIpNeighborMonitor"
322         )
323     }
324 
325     @After
tearDownnull326     fun tearDown() {
327         // Ensure the handler thread is not accessing the fd while changing its mock
328         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
329         doReturn(false).`when`(fd).valid()
330         handlerThread.quitSafely()
331     }
332 
333     @Test
testLoseProvisioning_FirstProbeIsFailednull334     fun testLoseProvisioning_FirstProbeIsFailed() {
335         reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES)
336 
337         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_FAILED))
338         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
339             anyString(),
340             eq(NUD_ORGANIC_FAILED_CRITICAL)
341         )
342     }
343 
runLoseProvisioningTestnull344     private fun runLoseProvisioningTest(
345         newLp: LinkProperties,
346         lostNeighbor: InetAddress,
347         eventType: NudEventType
348     ) {
349         runLoseProvisioningTest(
350                 newLp,
351                 lostNeighbor,
352                 eventType,
353                 false, /* everReachable */
354                 true /* expectedNotifyLost */
355         )
356     }
357 
runLoseProvisioningTestnull358     private fun runLoseProvisioningTest(
359         newLp: LinkProperties,
360         lostNeighbor: InetAddress,
361         eventType: NudEventType,
362         everReachable: Boolean,
363         expectedNotifyLost: Boolean
364     ) {
365         reachabilityMonitor.updateLinkProperties(newLp)
366 
367         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_STALE))
368         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_STALE))
369         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_STALE))
370         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_STALE))
371         if (everReachable) {
372             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
373             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
374             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_REACHABLE))
375             neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_REACHABLE))
376         }
377 
378         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_PROBE))
379         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
380         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
381 
382         if (expectedNotifyLost) {
383             verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
384                 anyString(),
385                 eq(eventType)
386             )
387         } else {
388              verify(callback, never()).notifyLost(anyString(), any())
389         }
390     }
391 
verifyNudFailureMetricsnull392     private fun verifyNudFailureMetrics(
393         eventType: NudEventType,
394         ipType: IpType,
395         lostNeighborType: NudNeighborType
396     ) {
397         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS)).setNudIpType(eq(ipType))
398         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
399                 .setNudEventType(eq(eventType))
400         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
401                 .setNudNeighborType(eq(lostNeighborType))
402     }
403 
verifyNudFailureMetricsNotReportednull404     private fun verifyNudFailureMetricsNotReported(
405     ) {
406         verify(mIpReachabilityMonitorMetrics, never()).setNudIpType(any())
407         verify(mIpReachabilityMonitorMetrics, never()).setNudEventType(any())
408         verify(mIpReachabilityMonitorMetrics, never()).setNudNeighborType(any())
409     }
410 
411     // Verify if the notifyLost will be called when one neighbor has lost but it's still
412     // provisioned.
runLoseNeighborStillProvisionedTestnull413     private fun runLoseNeighborStillProvisionedTest(
414         newLp: LinkProperties,
415         lostNeighbor: InetAddress,
416         eventType: NudEventType,
417         ipType: IpType,
418         lostNeighborType: NudNeighborType
419     ) {
420         reachabilityMonitor.updateLinkProperties(newLp)
421 
422         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
423         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
424         verify(callback, never()).notifyLost(anyString(), any(NudEventType::class.java))
425         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
426     }
427 
prepareNeighborReachableButMacAddrChangedTestnull428     private fun prepareNeighborReachableButMacAddrChangedTest(
429         newLp: LinkProperties,
430         neighbor: InetAddress,
431         macaddr: String
432     ) {
433         reachabilityMonitor.updateLinkProperties(newLp)
434 
435         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, macaddr))
436         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
437         verify(callback, never()).notifyLost(
438             anyString(),
439             any(NudEventType::class.java)
440         )
441     }
442 
443     @Test
testLoseProvisioning_Ipv4DnsLostnull444     fun testLoseProvisioning_Ipv4DnsLost() {
445         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS, NUD_ORGANIC_FAILED_CRITICAL)
446     }
447 
448     @Test
testLoseProvisioning_Ipv6DnsLostnull449     fun testLoseProvisioning_Ipv6DnsLost() {
450         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS, NUD_ORGANIC_FAILED_CRITICAL)
451     }
452 
453     @Test
testLoseProvisioning_Ipv4GatewayLostnull454     fun testLoseProvisioning_Ipv4GatewayLost() {
455         runLoseProvisioningTest(
456             TEST_LINK_PROPERTIES,
457             TEST_IPV4_GATEWAY,
458             NUD_ORGANIC_FAILED_CRITICAL
459         )
460     }
461 
462     @Test
testLoseProvisioning_Ipv6GatewayLostnull463     fun testLoseProvisioning_Ipv6GatewayLost() {
464         runLoseProvisioningTest(
465             TEST_LINK_PROPERTIES,
466             TEST_IPV6_GATEWAY,
467             NUD_ORGANIC_FAILED_CRITICAL
468         )
469     }
470 
471     @Test
472     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv4DnsLostnull473     fun testLoseProvisioning_ignoreOrganicIpv4DnsLost() {
474         runLoseProvisioningTest(
475             TEST_LINK_PROPERTIES,
476             TEST_IPV4_DNS,
477             NUD_ORGANIC_FAILED_CRITICAL,
478             false /* everReachable */,
479             false /* expectedNotifyLost */
480         )
481     }
482 
483     @Test
484     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv6DnsLostnull485     fun testLoseProvisioning_ignoreOrganicIpv6DnsLost() {
486         runLoseProvisioningTest(
487             TEST_LINK_PROPERTIES,
488             TEST_IPV6_DNS,
489             NUD_ORGANIC_FAILED_CRITICAL,
490             false /* everReachable */,
491             false /* expectedNotifyLost */
492         )
493     }
494 
495     @Test
496     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv4GatewayLostnull497     fun testLoseProvisioning_ignoreOrganicIpv4GatewayLost() {
498         runLoseProvisioningTest(
499             TEST_LINK_PROPERTIES,
500             TEST_IPV4_GATEWAY,
501             NUD_ORGANIC_FAILED_CRITICAL,
502             false /* everReachable */,
503             false /* expectedNotifyLost */
504         )
505     }
506 
507     @Test
508     @Flag(name = IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION, enabled = true)
testLoseProvisioning_ignoreOrganicIpv6GatewayLostnull509     fun testLoseProvisioning_ignoreOrganicIpv6GatewayLost() {
510         runLoseProvisioningTest(
511             TEST_LINK_PROPERTIES,
512             TEST_IPV6_GATEWAY,
513             NUD_ORGANIC_FAILED_CRITICAL,
514             false /* everReachable */,
515             false /* expectedNotifyLost */
516         )
517     }
518 
519     @Test
520     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_ignoreNeverReachableIpv6GatewayLostnull521     fun testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost() {
522         runLoseProvisioningTest(
523             TEST_LINK_PROPERTIES,
524             TEST_IPV6_GATEWAY,
525             NUD_ORGANIC_FAILED_CRITICAL,
526             false /* everReachable */,
527             false /* expectedNotifyLost */
528         )
529     }
530 
531     @Test
532     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_ignoreNeverReachableIpv6DnsLostnull533     fun testLoseProvisioning_ignoreNeverReachableIpv6DnsLost() {
534         runLoseProvisioningTest(
535             TEST_LINK_PROPERTIES,
536             TEST_IPV6_DNS,
537             NUD_ORGANIC_FAILED_CRITICAL,
538             false /* everReachable */,
539             false /* expectedNotifyLost */
540         )
541     }
542 
543     @Test
544     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_notIgnoreEverReachableIpv6GatewayLostnull545     fun testLoseProvisioning_notIgnoreEverReachableIpv6GatewayLost() {
546         runLoseProvisioningTest(
547             TEST_LINK_PROPERTIES,
548             TEST_IPV6_GATEWAY,
549             NUD_ORGANIC_FAILED_CRITICAL,
550             true /* everReachable */,
551             true /* expectedNotifyLost */
552         )
553     }
554 
555     @Test
556     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_notIgnoreEverReachableIpv6DnsLostnull557     fun testLoseProvisioning_notIgnoreEverReachableIpv6DnsLost() {
558         runLoseProvisioningTest(
559             TEST_LINK_PROPERTIES,
560             TEST_IPV6_DNS,
561             NUD_ORGANIC_FAILED_CRITICAL,
562             true /* everReachable */,
563             true /* expectedNotifyLost */
564         )
565     }
566 
567     @Test
568     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_ignoreNeverReachableIpv4DnsLostnull569     fun testLoseProvisioning_ignoreNeverReachableIpv4DnsLost() {
570         runLoseProvisioningTest(
571             TEST_LINK_PROPERTIES,
572             TEST_IPV4_DNS,
573             NUD_ORGANIC_FAILED_CRITICAL,
574             false /* everReachable */,
575             false /* expectedNotifyLost */
576         )
577     }
578 
579     @Test
580     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_notIgnoreEverReachableIpv4GatewayLostnull581     fun testLoseProvisioning_notIgnoreEverReachableIpv4GatewayLost() {
582         runLoseProvisioningTest(
583             TEST_LINK_PROPERTIES,
584             TEST_IPV4_GATEWAY,
585             NUD_ORGANIC_FAILED_CRITICAL,
586             true /* everReachable */,
587             true /* expectedNotifyLost */
588         )
589     }
590 
591     @Test
592     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_notIgnoreEverReachableIpv4DnsLostnull593     fun testLoseProvisioning_notIgnoreEverReachableIpv4DnsLost() {
594         runLoseProvisioningTest(
595             TEST_LINK_PROPERTIES,
596             TEST_IPV4_DNS,
597             NUD_ORGANIC_FAILED_CRITICAL,
598             true /* everReachable */,
599             true /* expectedNotifyLost */
600         )
601     }
602 
603     @Test
604     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost_withTwoIPv6DnsServersnull605     fun testLoseProvisioning_ignoreNeverReachableIpv6GatewayLost_withTwoIPv6DnsServers() {
606         reachabilityMonitor.updateLinkProperties(TEST_DUAL_LINK_PROPERTIES)
607 
608         // IPv6 default router is never reachable, but two DNS servers do.
609         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
610         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
611         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_REACHABLE))
612         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_REACHABLE))
613 
614         // Push a NUD_FAILED event to IPv6 default router, this event should not trigger
615         // onReachabilityFailure callback given it's never reachable.
616         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_PROBE))
617         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_FAILED))
618         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
619 
620         verify(callback, never()).notifyLost(anyString(), any())
621 
622         // Then another NUD_FAILED from one of DNS servers, this event should not trigger
623         // onReachabilityFailure callback either.
624         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_PROBE))
625         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_FAILED))
626         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
627 
628         verify(callback, never()).notifyLost(anyString(), any())
629 
630         // Then we lost all IPv6 DNS servers, onReachabilityFailure callback should be triggered.
631         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_PROBE))
632         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS2, NUD_FAILED))
633         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
634 
635         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
636             anyString(),
637             eq(NUD_ORGANIC_FAILED_CRITICAL)
638         )
639     }
640 
641     @Test
642     @Flag(name = IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION, enabled = true)
testLoseProvisioning_ignoreNeverReachableIpv6DnsLost_withTwoIPv6Routesnull643     fun testLoseProvisioning_ignoreNeverReachableIpv6DnsLost_withTwoIPv6Routes() {
644         val TEST_DUAL_IPV6_ROUTERS_LINK_PROPERTIES = LinkProperties().apply {
645             interfaceName = TEST_IFACE.name
646             addLinkAddress(TEST_IPV4_LINKADDR)
647             addLinkAddress(TEST_IPV6_LINKADDR)
648             addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
649 
650             // Add on link routes
651             addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
652             addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
653             addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
654 
655             // Add default routes: one IPv4 default route and two IPv6 default routes.
656             addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
657             addRoute(
658                 RouteInfo(
659                     IpPrefix(parseNumericAddress("::"), 0),
660                     TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY
661                 )
662             )
663             addRoute(
664                 RouteInfo(
665                     IpPrefix(parseNumericAddress("::"), 0),
666                     TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY2
667                 )
668             )
669 
670             addDnsServer(TEST_IPV4_DNS)
671             addDnsServer(TEST_IPV6_DNS)
672         }
673 
674         reachabilityMonitor.updateLinkProperties(TEST_DUAL_IPV6_ROUTERS_LINK_PROPERTIES)
675 
676         // IPv6 DNS is never reachable, but two default gateways do.
677         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_REACHABLE))
678         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_REACHABLE))
679         neighborMonitor.enqueuePacket(
680             makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_REACHABLE)
681         )
682         neighborMonitor.enqueuePacket(
683             makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_REACHABLE)
684         )
685 
686         // Push a NUD_FAILED event to IPv6 DNS server, this event should not trigger
687         // onReachabilityFailure callback given it's never reachable.
688         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_PROBE))
689         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_FAILED))
690         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
691 
692         verify(callback, never()).notifyLost(anyString(), any())
693 
694         // Then another NUD_FAILED from one of IPv6 gateways, this event should not trigger
695         // onReachabilityFailure callback either.
696         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_PROBE))
697         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY, NUD_FAILED))
698         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
699 
700         verify(callback, never()).notifyLost(anyString(), any())
701 
702         // Then we lost all IPv6 gateways, onReachabilityFailure callback should be triggered.
703         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_PROBE))
704         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_LINKLOCAL_GATEWAY2, NUD_FAILED))
705         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
706 
707         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
708             anyString(),
709             eq(NUD_ORGANIC_FAILED_CRITICAL)
710         )
711     }
712 
runNudProbeFailureMetricsTestnull713     private fun runNudProbeFailureMetricsTest(
714         lp: LinkProperties,
715         lostNeighbor: InetAddress,
716         eventType: NudEventType,
717         ipType: IpType,
718         lostNeighborType: NudNeighborType
719     ) {
720         runLoseProvisioningTest(lp, lostNeighbor, eventType)
721         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
722     }
723 
724     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostPostRoamingnull725     fun testNudProbeFailedMetrics_Ipv6GatewayLostPostRoaming() {
726         reachabilityMonitor.probeAll(true /* dueToRoam */)
727         runNudProbeFailureMetricsTest(
728             TEST_LINK_PROPERTIES,
729             TEST_IPV6_GATEWAY,
730             NUD_POST_ROAMING_FAILED_CRITICAL,
731             IPV6,
732             NUD_NEIGHBOR_GATEWAY
733         )
734     }
735 
736     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostPostRoamingnull737     fun testNudProbeFailedMetrics_Ipv4GatewayLostPostRoaming() {
738         reachabilityMonitor.probeAll(true /* dueToRoam */)
739         runNudProbeFailureMetricsTest(
740             TEST_LINK_PROPERTIES,
741             TEST_IPV4_GATEWAY,
742             NUD_POST_ROAMING_FAILED_CRITICAL,
743             IPV4,
744             NUD_NEIGHBOR_GATEWAY
745         )
746     }
747 
748     @Test
testNudProbeFailedMetrics_Ipv6DnsLostPostRoamingnull749     fun testNudProbeFailedMetrics_Ipv6DnsLostPostRoaming() {
750         reachabilityMonitor.probeAll(true /* dueToRoam */)
751         runNudProbeFailureMetricsTest(
752             TEST_LINK_PROPERTIES,
753             TEST_IPV6_DNS,
754             NUD_POST_ROAMING_FAILED_CRITICAL,
755             IPV6,
756             NUD_NEIGHBOR_DNS
757         )
758     }
759 
760     @Test
testNudProbeFailedMetrics_Ipv4DnsLostPostRoamingnull761     fun testNudProbeFailedMetrics_Ipv4DnsLostPostRoaming() {
762         reachabilityMonitor.probeAll(true /* dueToRoam */)
763         runNudProbeFailureMetricsTest(
764             TEST_LINK_PROPERTIES,
765             TEST_IPV4_DNS,
766             NUD_POST_ROAMING_FAILED_CRITICAL,
767             IPV4,
768             NUD_NEIGHBOR_DNS
769         )
770     }
771 
772     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoamingnull773     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoaming() {
774         reachabilityMonitor.probeAll(true /* dueToRoam */)
775         runNudProbeFailureMetricsTest(
776             TEST_IPV4_ONLY_LINK_PROPERTIES,
777             TEST_IPV4_GATEWAY_DNS,
778             NUD_POST_ROAMING_FAILED_CRITICAL,
779             IPV4,
780             NUD_NEIGHBOR_BOTH
781         )
782     }
783 
784     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoamingnull785     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoaming() {
786         reachabilityMonitor.probeAll(true /* dueToRoam */)
787         runNudProbeFailureMetricsTest(
788             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
789             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
790             NUD_POST_ROAMING_FAILED_CRITICAL,
791             IPV6,
792             NUD_NEIGHBOR_GATEWAY
793         )
794     }
795 
796     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirmnull797     fun testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirm() {
798         reachabilityMonitor.probeAll(false /* dueToRoam */)
799         runNudProbeFailureMetricsTest(
800             TEST_LINK_PROPERTIES,
801             TEST_IPV6_GATEWAY,
802             NUD_CONFIRM_FAILED_CRITICAL,
803             IPV6,
804             NUD_NEIGHBOR_GATEWAY
805         )
806     }
807 
808     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirmnull809     fun testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirm() {
810         reachabilityMonitor.probeAll(false /* dueToRoam */)
811         runNudProbeFailureMetricsTest(
812             TEST_LINK_PROPERTIES,
813             TEST_IPV4_GATEWAY,
814             NUD_CONFIRM_FAILED_CRITICAL,
815             IPV4,
816             NUD_NEIGHBOR_GATEWAY
817         )
818     }
819 
820     @Test
testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirmnull821     fun testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirm() {
822         reachabilityMonitor.probeAll(false /* dueToRoam */)
823         runNudProbeFailureMetricsTest(
824             TEST_LINK_PROPERTIES,
825             TEST_IPV6_DNS,
826             NUD_CONFIRM_FAILED_CRITICAL,
827             IPV6,
828             NUD_NEIGHBOR_DNS
829         )
830     }
831 
832     @Test
testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirmnull833     fun testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirm() {
834         reachabilityMonitor.probeAll(false /* dueToRoam */)
835         runNudProbeFailureMetricsTest(
836             TEST_LINK_PROPERTIES,
837             TEST_IPV4_DNS,
838             NUD_CONFIRM_FAILED_CRITICAL,
839             IPV4,
840             NUD_NEIGHBOR_DNS
841         )
842     }
843 
844     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirmnull845     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirm() {
846         reachabilityMonitor.probeAll(false /* dueToRoam */)
847         runNudProbeFailureMetricsTest(
848             TEST_IPV4_ONLY_LINK_PROPERTIES,
849             TEST_IPV4_GATEWAY_DNS,
850             NUD_CONFIRM_FAILED_CRITICAL,
851             IPV4,
852             NUD_NEIGHBOR_BOTH
853         )
854     }
855 
856     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirmnull857     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirm() {
858         reachabilityMonitor.probeAll(false /* dueToRoam */)
859         runNudProbeFailureMetricsTest(
860             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
861             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
862             NUD_CONFIRM_FAILED_CRITICAL,
863             IPV6,
864                 NUD_NEIGHBOR_GATEWAY
865         )
866     }
867 
868     @Test
testNudProbeFailedMetrics_IPv6GatewayLostOrganicnull869     fun testNudProbeFailedMetrics_IPv6GatewayLostOrganic() {
870         runNudProbeFailureMetricsTest(
871             TEST_LINK_PROPERTIES,
872             TEST_IPV6_GATEWAY,
873             NUD_ORGANIC_FAILED_CRITICAL,
874             IPV6,
875             NUD_NEIGHBOR_GATEWAY
876         )
877     }
878 
879     @Test
testNudProbeFailedMetrics_IPv4GatewayLostOrganicnull880     fun testNudProbeFailedMetrics_IPv4GatewayLostOrganic() {
881         runNudProbeFailureMetricsTest(
882             TEST_LINK_PROPERTIES,
883             TEST_IPV4_GATEWAY,
884             NUD_ORGANIC_FAILED_CRITICAL,
885             IPV4,
886             NUD_NEIGHBOR_GATEWAY
887         )
888     }
889 
890     @Test
testNudProbeFailedMetrics_IPv6DnsLostOrganicnull891     fun testNudProbeFailedMetrics_IPv6DnsLostOrganic() {
892         runNudProbeFailureMetricsTest(
893             TEST_LINK_PROPERTIES,
894             TEST_IPV6_DNS,
895             NUD_ORGANIC_FAILED_CRITICAL,
896             IPV6,
897             NUD_NEIGHBOR_DNS
898         )
899     }
900 
901     @Test
testNudProbeFailedMetrics_IPv4DnsLostOrganicnull902     fun testNudProbeFailedMetrics_IPv4DnsLostOrganic() {
903         runNudProbeFailureMetricsTest(
904             TEST_LINK_PROPERTIES,
905             TEST_IPV4_DNS,
906             NUD_ORGANIC_FAILED_CRITICAL,
907             IPV4,
908             NUD_NEIGHBOR_DNS
909         )
910     }
911 
912     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganicnull913     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganic() {
914         runNudProbeFailureMetricsTest(
915             TEST_IPV4_ONLY_LINK_PROPERTIES,
916             TEST_IPV4_GATEWAY_DNS,
917             NUD_ORGANIC_FAILED_CRITICAL,
918             IPV4,
919             NUD_NEIGHBOR_BOTH
920         )
921     }
922 
923     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganicnull924     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganic() {
925         runNudProbeFailureMetricsTest(
926             TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
927             TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY,
928             NUD_ORGANIC_FAILED_CRITICAL,
929             IPV6,
930                 NUD_NEIGHBOR_GATEWAY
931         )
932     }
933 
934     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoamingnull935     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoaming() {
936         reachabilityMonitor.probeAll(true /* dueToRoam */)
937         runLoseNeighborStillProvisionedTest(
938             TEST_DUAL_LINK_PROPERTIES,
939             TEST_IPV6_DNS,
940             NUD_POST_ROAMING_FAILED,
941             IPV6,
942             NUD_NEIGHBOR_DNS
943         )
944     }
945 
946     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirmnull947     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirm() {
948         reachabilityMonitor.probeAll(false /* dueToRoam */)
949         runLoseNeighborStillProvisionedTest(
950             TEST_DUAL_LINK_PROPERTIES,
951             TEST_IPV6_DNS,
952             NUD_CONFIRM_FAILED,
953             IPV6,
954             NUD_NEIGHBOR_DNS
955         )
956     }
957 
958     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganicnull959     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganic() {
960         runLoseNeighborStillProvisionedTest(
961             TEST_DUAL_LINK_PROPERTIES,
962             TEST_IPV6_DNS,
963             NUD_ORGANIC_FAILED,
964             IPV6,
965             NUD_NEIGHBOR_DNS
966         )
967     }
968 
969     @Test
testNudProbeFailedMetrics_multipleProbesFromRoamFirstnull970     fun testNudProbeFailedMetrics_multipleProbesFromRoamFirst() {
971         reachabilityMonitor.probeAll(true /* dueToRoam */)
972         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
973         Thread.sleep(2)
974         reachabilityMonitor.probeAll(false /* dueToRoam */)
975         runLoseProvisioningTest(
976             TEST_LINK_PROPERTIES,
977             TEST_IPV6_GATEWAY,
978             NUD_POST_ROAMING_FAILED_CRITICAL
979         )
980 
981         verifyNudFailureMetrics(NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
982     }
983 
984     @Test
testNudProbeFailedMetrics_multipleProbesFromConfirmFirstnull985     fun testNudProbeFailedMetrics_multipleProbesFromConfirmFirst() {
986         reachabilityMonitor.probeAll(false /* dueToRoam */)
987         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
988         Thread.sleep(2)
989         reachabilityMonitor.probeAll(true /* dueToRoam */)
990         runLoseProvisioningTest(
991             TEST_LINK_PROPERTIES,
992             TEST_IPV6_GATEWAY,
993             NUD_CONFIRM_FAILED_CRITICAL
994         )
995 
996         verifyNudFailureMetrics(NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
997     }
998 
probeWithNeighborEventnull999     private fun probeWithNeighborEvent(dueToRoam: Boolean, neighbor: InetAddress, macaddr: String) {
1000         reachabilityMonitor.probeAll(dueToRoam)
1001         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_PROBE, macaddr))
1002     }
1003 
verifyNudMacAddrChangednull1004     private fun verifyNudMacAddrChanged(
1005         neighbor: InetAddress,
1006         eventType: NudEventType,
1007         ipType: IpType
1008     ) {
1009         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, TEST_MAC_2))
1010         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(
1011             anyString(),
1012             eq(eventType)
1013         )
1014         verifyNudFailureMetrics(eventType, ipType, NUD_NEIGHBOR_GATEWAY)
1015     }
1016 
verifyNudMacAddrChangeNotReportednull1017     private fun verifyNudMacAddrChangeNotReported(
1018         neighbor: InetAddress,
1019     ) {
1020         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE, TEST_MAC_2))
1021         verify(callback, never()).notifyLost(anyString(), any())
1022         verifyNudFailureMetricsNotReported()
1023     }
1024 
1025     @Test
1026     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1027     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoamingnull1028     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoaming() {
1029         prepareNeighborReachableButMacAddrChangedTest(
1030             TEST_LINK_PROPERTIES,
1031             TEST_IPV6_GATEWAY,
1032             TEST_MAC_1
1033         )
1034         probeWithNeighborEvent(true /* dueToRoam */, TEST_IPV6_GATEWAY, TEST_MAC_1)
1035         verifyNudMacAddrChanged(TEST_IPV6_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV6)
1036     }
1037 
1038     @Test
1039     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1040     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoamingnull1041     fun testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoaming() {
1042         prepareNeighborReachableButMacAddrChangedTest(
1043             TEST_LINK_PROPERTIES,
1044             TEST_IPV4_GATEWAY,
1045             TEST_MAC_1
1046         )
1047 
1048         probeWithNeighborEvent(true /* dueToRoam */, TEST_IPV4_GATEWAY, TEST_MAC_1)
1049         verifyNudMacAddrChanged(TEST_IPV4_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV4)
1050     }
1051 
1052     @Test
1053     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1054     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirmnull1055     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirm() {
1056         prepareNeighborReachableButMacAddrChangedTest(
1057             TEST_LINK_PROPERTIES,
1058             TEST_IPV6_GATEWAY,
1059             TEST_MAC_1
1060         )
1061 
1062         reachabilityMonitor.probeAll(false /* dueToRoam */)
1063         verifyNudMacAddrChangeNotReported(TEST_IPV6_GATEWAY)
1064     }
1065 
1066     @Test
1067     @Flag(name = IP_REACHABILITY_MCAST_RESOLICIT_VERSION, true)
1068     @Flag(name = IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION, enabled = true)
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganicnull1069     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganic() {
1070         prepareNeighborReachableButMacAddrChangedTest(
1071             TEST_LINK_PROPERTIES,
1072             TEST_IPV6_GATEWAY,
1073             TEST_MAC_1
1074         )
1075 
1076         verifyNudMacAddrChangeNotReported(TEST_IPV6_GATEWAY)
1077     }
1078 
1079     @SuppressLint("NewApi")
1080     @Test
testIsOnLinknull1081     fun testIsOnLink() {
1082         val routes: List<RouteInfo> = listOf(
1083                 RouteInfo(
1084                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
1085                         null /* gateway */,
1086                         null /* iface */,
1087                         RouteInfo.RTN_THROW
1088                 ),
1089                 RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), null /* gateway */)
1090         )
1091 
1092         assertTrue(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
1093     }
1094 
1095     @SuppressLint("NewApi")
1096     @Test
testIsOnLink_withThrowRoutesnull1097     fun testIsOnLink_withThrowRoutes() {
1098         val routes: List<RouteInfo> = listOf(
1099                 RouteInfo(
1100                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
1101                         null /* gateway */,
1102                         null /* iface */,
1103                         RouteInfo.RTN_THROW
1104                 )
1105         )
1106 
1107         assertFalse(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
1108     }
1109 }
1110