• 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 package android.net.ip
17 
18 import android.annotation.SuppressLint
19 import android.content.Context
20 import android.net.INetd
21 import android.net.InetAddresses.parseNumericAddress
22 import android.net.IpPrefix
23 import android.net.LinkAddress
24 import android.net.LinkProperties
25 import android.net.RouteInfo
26 import android.net.metrics.IpConnectivityLog
27 import com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION
28 import android.os.Handler
29 import android.os.HandlerThread
30 import android.os.MessageQueue
31 import android.os.MessageQueue.OnFileDescriptorEventListener
32 import android.stats.connectivity.IpType
33 import android.stats.connectivity.IpType.IPV4
34 import android.stats.connectivity.IpType.IPV6
35 import android.stats.connectivity.NudEventType
36 import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED
37 import android.stats.connectivity.NudEventType.NUD_CONFIRM_FAILED_CRITICAL
38 import android.stats.connectivity.NudEventType.NUD_CONFIRM_MAC_ADDRESS_CHANGED
39 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED
40 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
41 import android.stats.connectivity.NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED
42 import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED
43 import android.stats.connectivity.NudEventType.NUD_ORGANIC_FAILED_CRITICAL
44 import android.stats.connectivity.NudEventType.NUD_ORGANIC_MAC_ADDRESS_CHANGED
45 import android.stats.connectivity.NudNeighborType
46 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_BOTH
47 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_DNS
48 import android.stats.connectivity.NudNeighborType.NUD_NEIGHBOR_GATEWAY
49 import android.system.ErrnoException
50 import android.system.OsConstants.EAGAIN
51 import androidx.test.filters.SmallTest
52 import androidx.test.runner.AndroidJUnit4
53 import com.android.networkstack.metrics.IpReachabilityMonitorMetrics
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_REACHABLE
59 import com.android.net.module.util.netlink.StructNdMsg.NUD_STALE
60 import com.android.testutils.makeNewNeighMessage
61 import com.android.testutils.waitForIdle
62 import org.junit.After
63 import org.junit.Before
64 import org.junit.Test
65 import org.junit.runner.RunWith
66 import org.mockito.ArgumentCaptor
67 import org.mockito.ArgumentMatchers.any
68 import org.mockito.ArgumentMatchers.anyBoolean
69 import org.mockito.ArgumentMatchers.anyInt
70 import org.mockito.ArgumentMatchers.anyObject
71 import org.mockito.ArgumentMatchers.anyString
72 import org.mockito.ArgumentMatchers.eq
73 import org.mockito.Mockito.doAnswer
74 import org.mockito.Mockito.doReturn
75 import org.mockito.Mockito.mock
76 import org.mockito.Mockito.never
77 import org.mockito.Mockito.timeout
78 import org.mockito.Mockito.verify
79 import java.io.FileDescriptor
80 import java.net.Inet4Address
81 import java.net.Inet6Address
82 import java.net.InetAddress
83 import java.util.concurrent.CompletableFuture
84 import java.util.concurrent.ConcurrentLinkedQueue
85 import java.util.concurrent.TimeUnit
86 import kotlin.test.assertFalse
87 import kotlin.test.assertTrue
88 import kotlin.test.fail
89 
90 private const val TEST_TIMEOUT_MS = 10_000L
91 
92 private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
93 private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
94 
95 // IPv4 gateway is also DNS server.
96 private val TEST_IPV4_GATEWAY_DNS = parseNumericAddress("192.168.222.100") as Inet4Address
97 
98 private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
99 private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
100 
101 private val TEST_IPV6_LINKLOCAL_LINKADDR = LinkAddress("fe80::123/64")
102 private val TEST_IPV6_LINKLOCAL_GATEWAY = parseNumericAddress("fe80::1") as Inet6Address
103 private val TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY = parseNumericAddress("fe80::1%21") as Inet6Address
104 
105 // DNSes inside IP prefix
106 private val TEST_IPV4_DNS = parseNumericAddress("192.168.222.1") as Inet4Address
107 private val TEST_IPV6_DNS = parseNumericAddress("2001:db8::321") as Inet6Address
108 private val TEST_IPV6_DNS2 = parseNumericAddress("2001:db8::456") as Inet6Address
109 
110 private val TEST_IFACE = InterfaceParams("fake0", 21, null)
111 
112 @SuppressLint("NewApi")
113 private val TEST_LINK_PROPERTIES = LinkProperties().apply {
114     interfaceName = TEST_IFACE.name
115     addLinkAddress(TEST_IPV4_LINKADDR)
116     addLinkAddress(TEST_IPV6_LINKADDR)
117 
118     // Add on link routes
119     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
120     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
121 
122     // Add default routes
123     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
124     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
125 
126     addDnsServer(TEST_IPV4_DNS)
127     addDnsServer(TEST_IPV6_DNS)
128 }
129 
130 @SuppressLint("NewApi")
<lambda>null131 private val TEST_IPV4_ONLY_LINK_PROPERTIES = LinkProperties().apply {
132     interfaceName = TEST_IFACE.name
133     addLinkAddress(TEST_IPV4_LINKADDR)
134 
135     // Add on link routes
136     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
137 
138     // Add default routes
139     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY_DNS))
140 
141     addDnsServer(TEST_IPV4_GATEWAY_DNS)
142 }
143 
144 @SuppressLint("NewApi")
<lambda>null145 private val TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES = LinkProperties().apply {
146     interfaceName = TEST_IFACE.name
147     addLinkAddress(TEST_IPV6_LINKADDR)
148     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
149 
150     // Add on link routes
151     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
152     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
153 
154     // Add default routes
155     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
156 
157     addDnsServer(TEST_IPV6_DNS)
158 }
159 
160 @SuppressLint("NewApi")
<lambda>null161 private val TEST_DUAL_LINK_PROPERTIES = LinkProperties().apply {
162     interfaceName = TEST_IFACE.name
163     addLinkAddress(TEST_IPV4_LINKADDR)
164     addLinkAddress(TEST_IPV6_LINKADDR)
165     addLinkAddress(TEST_IPV6_LINKLOCAL_LINKADDR)
166 
167     // Add on link routes
168     addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name))
169     addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name))
170     addRoute(RouteInfo(TEST_IPV6_LINKLOCAL_LINKADDR, null /* gateway */, TEST_IFACE.name))
171 
172     // Add default routes
173     addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
174     addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY))
175 
176     addDnsServer(TEST_IPV4_DNS)
177     addDnsServer(TEST_IPV6_DNS)
178     addDnsServer(TEST_IPV6_DNS2)
179 }
180 
181 /**
182  * Tests for IpReachabilityMonitor.
183  */
184 @RunWith(AndroidJUnit4::class)
185 @SmallTest
186 class IpReachabilityMonitorTest {
187     private val callback = mock(IpReachabilityMonitor.Callback::class.java)
188     private val dependencies = mock(IpReachabilityMonitor.Dependencies::class.java)
189     private val log = mock(SharedLog::class.java)
190     private val context = mock(Context::class.java)
191     private val netd = mock(INetd::class.java)
192     private val fd = mock(FileDescriptor::class.java)
193     private val metricsLog = mock(IpConnectivityLog::class.java)
194     private val mIpReachabilityMonitorMetrics = mock(IpReachabilityMonitorMetrics::class.java)
195 
196     private val handlerThread = HandlerThread(IpReachabilityMonitorTest::class.simpleName)
<lambda>null197     private val handler by lazy { Handler(handlerThread.looper) }
198 
199     private lateinit var reachabilityMonitor: IpReachabilityMonitor
200     private lateinit var neighborMonitor: TestIpNeighborMonitor
201 
202     /**
203      * A version of [IpNeighborMonitor] that overrides packet reading from a socket, and instead
204      * allows the test to enqueue test packets via [enqueuePacket].
205      */
206     private class TestIpNeighborMonitor(
207         handler: Handler,
208         log: SharedLog,
209         cb: NeighborEventConsumer,
210         private val fd: FileDescriptor
211     ) : IpNeighborMonitor(handler, log, cb) {
212 
213         private val pendingPackets = ConcurrentLinkedQueue<ByteArray>()
214         val msgQueue = mock(MessageQueue::class.java)
215 
216         private var eventListener: OnFileDescriptorEventListener? = null
217 
createFdnull218         override fun createFd() = fd
219         override fun getMessageQueue() = msgQueue
220 
221         fun enqueuePacket(packet: ByteArray) {
222             val listener = eventListener ?: fail("IpNeighborMonitor was not yet started")
223             pendingPackets.add(packet)
224             handler.post {
225                 listener.onFileDescriptorEvents(fd, OnFileDescriptorEventListener.EVENT_INPUT)
226             }
227         }
228 
readPacketnull229         override fun readPacket(fd: FileDescriptor, packetBuffer: ByteArray): Int {
230             val packet = pendingPackets.poll() ?: throw ErrnoException("No pending packet", EAGAIN)
231             if (packet.size > packetBuffer.size) {
232                 fail("Buffer (${packetBuffer.size}) is too small for packet (${packet.size})")
233             }
234             System.arraycopy(packet, 0, packetBuffer, 0, packet.size)
235             return packet.size
236         }
237 
onStartnull238         override fun onStart() {
239             super.onStart()
240 
241             // Find the file descriptor listener that was registered on the instrumented queue
242             val captor = ArgumentCaptor.forClass(OnFileDescriptorEventListener::class.java)
243             verify(msgQueue).addOnFileDescriptorEventListener(
244                     eq(fd), anyInt(), captor.capture())
245             eventListener = captor.value
246         }
247     }
248 
249     @Before
setUpnull250     fun setUp() {
251         doReturn(log).`when`(log).forSubComponent(anyString())
252         doReturn(true).`when`(fd).valid()
253         handlerThread.start()
254 
255         doAnswer { inv ->
256             val handler = inv.getArgument<Handler>(0)
257             val log = inv.getArgument<SharedLog>(1)
258             val cb = inv.getArgument<IpNeighborMonitor.NeighborEventConsumer>(2)
259             neighborMonitor = TestIpNeighborMonitor(handler, log, cb, fd)
260             neighborMonitor
261         }.`when`(dependencies).makeIpNeighborMonitor(any(), any(), any())
262         doReturn(mIpReachabilityMonitorMetrics)
263                 .`when`(dependencies).getIpReachabilityMonitorMetrics()
264         doReturn(true).`when`(dependencies).isFeatureEnabled(anyObject(),
265                 eq(IP_REACHABILITY_MCAST_RESOLICIT_VERSION), anyBoolean())
266 
267         val monitorFuture = CompletableFuture<IpReachabilityMonitor>()
268         // IpReachabilityMonitor needs to be started from the handler thread
269         handler.post {
270             monitorFuture.complete(IpReachabilityMonitor(
271                     context,
272                     TEST_IFACE,
273                     handler,
274                     log,
275                     callback,
276                     false /* useMultinetworkPolicyTracker */,
277                     dependencies,
278                     metricsLog,
279                     netd))
280         }
281         reachabilityMonitor = monitorFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
282         assertTrue(::neighborMonitor.isInitialized,
283                 "IpReachabilityMonitor did not call makeIpNeighborMonitor")
284     }
285 
286     @After
tearDownnull287     fun tearDown() {
288         // Ensure the handler thread is not accessing the fd while changing its mock
289         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
290         doReturn(false).`when`(fd).valid()
291         handlerThread.quitSafely()
292     }
293 
294     @Test
testLoseProvisioning_FirstProbeIsFailednull295     fun testLoseProvisioning_FirstProbeIsFailed() {
296         reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES)
297 
298         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_FAILED))
299         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(TEST_IPV4_DNS), anyString(),
300                 eq(NUD_ORGANIC_FAILED_CRITICAL))
301     }
302 
runLoseProvisioningTestnull303     private fun runLoseProvisioningTest(
304         newLp: LinkProperties,
305         lostNeighbor: InetAddress,
306         eventType: NudEventType
307     ) {
308         reachabilityMonitor.updateLinkProperties(newLp)
309 
310         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_STALE))
311         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_STALE))
312         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_STALE))
313         neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_STALE))
314 
315         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
316         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(lostNeighbor), anyString(),
317                 eq(eventType))
318     }
319 
verifyNudFailureMetricsnull320     private fun verifyNudFailureMetrics(
321         eventType: NudEventType,
322         ipType: IpType,
323         lostNeighborType: NudNeighborType
324     ) {
325         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS)).setNudIpType(eq(ipType))
326         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
327                 .setNudEventType(eq(eventType))
328         verify(mIpReachabilityMonitorMetrics, timeout(TEST_TIMEOUT_MS))
329                 .setNudNeighborType(eq(lostNeighborType))
330     }
331 
332     // Verify if the notifyLost will be called when one neighbor has lost but it's still
333     // provisioned.
runLoseNeighborStillProvisionedTestnull334     private fun runLoseNeighborStillProvisionedTest(
335         newLp: LinkProperties,
336         lostNeighbor: InetAddress,
337         eventType: NudEventType,
338         ipType: IpType,
339         lostNeighborType: NudNeighborType
340     ) {
341         reachabilityMonitor.updateLinkProperties(newLp)
342 
343         neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED))
344         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
345         verify(callback, never()).notifyLost(any(), anyString(), any(NudEventType::class.java))
346         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
347     }
348 
prepareNeighborReachableButMacAddrChangedTestnull349     private fun prepareNeighborReachableButMacAddrChangedTest(
350         newLp: LinkProperties,
351         neighbor: InetAddress
352     ) {
353         reachabilityMonitor.updateLinkProperties(newLp)
354 
355         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
356                 "001122334455" /* oldMac */))
357         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
358         verify(callback, never()).notifyLost(eq(neighbor), anyString(),
359                 any(NudEventType::class.java))
360     }
361 
362     @Test
testLoseProvisioning_Ipv4DnsLostnull363     fun testLoseProvisioning_Ipv4DnsLost() {
364         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS, NUD_ORGANIC_FAILED_CRITICAL)
365     }
366 
367     @Test
testLoseProvisioning_Ipv6DnsLostnull368     fun testLoseProvisioning_Ipv6DnsLost() {
369         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS, NUD_ORGANIC_FAILED_CRITICAL)
370     }
371 
372     @Test
testLoseProvisioning_Ipv4GatewayLostnull373     fun testLoseProvisioning_Ipv4GatewayLost() {
374         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
375                 NUD_ORGANIC_FAILED_CRITICAL)
376     }
377 
378     @Test
testLoseProvisioning_Ipv6GatewayLostnull379     fun testLoseProvisioning_Ipv6GatewayLost() {
380         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
381                 NUD_ORGANIC_FAILED_CRITICAL)
382     }
383 
runNudProbeFailureMetricsTestnull384     private fun runNudProbeFailureMetricsTest(
385         lp: LinkProperties,
386         lostNeighbor: InetAddress,
387         eventType: NudEventType,
388         ipType: IpType,
389         lostNeighborType: NudNeighborType
390     ) {
391         runLoseProvisioningTest(lp, lostNeighbor, eventType)
392         verifyNudFailureMetrics(eventType, ipType, lostNeighborType)
393     }
394 
395     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostPostRoamingnull396     fun testNudProbeFailedMetrics_Ipv6GatewayLostPostRoaming() {
397         reachabilityMonitor.probeAll(true /* dueToRoam */)
398         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
399                 NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
400     }
401 
402     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostPostRoamingnull403     fun testNudProbeFailedMetrics_Ipv4GatewayLostPostRoaming() {
404         reachabilityMonitor.probeAll(true /* dueToRoam */)
405         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
406                 NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
407     }
408 
409     @Test
testNudProbeFailedMetrics_Ipv6DnsLostPostRoamingnull410     fun testNudProbeFailedMetrics_Ipv6DnsLostPostRoaming() {
411         reachabilityMonitor.probeAll(true /* dueToRoam */)
412         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
413                 NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
414     }
415 
416     @Test
testNudProbeFailedMetrics_Ipv4DnsLostPostRoamingnull417     fun testNudProbeFailedMetrics_Ipv4DnsLostPostRoaming() {
418         reachabilityMonitor.probeAll(true /* dueToRoam */)
419         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
420                 NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
421     }
422 
423     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoamingnull424     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostPostRoaming() {
425         reachabilityMonitor.probeAll(true /* dueToRoam */)
426         runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
427                 NUD_POST_ROAMING_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
428     }
429 
430     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoamingnull431     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostPostRoaming() {
432         reachabilityMonitor.probeAll(true /* dueToRoam */)
433         runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
434                 TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_POST_ROAMING_FAILED_CRITICAL, IPV6,
435                 NUD_NEIGHBOR_GATEWAY)
436     }
437 
438     @Test
testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirmnull439     fun testNudProbeFailedMetrics_Ipv6GatewayLostAfterConfirm() {
440         reachabilityMonitor.probeAll(false /* dueToRoam */)
441         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
442                 NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
443     }
444 
445     @Test
testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirmnull446     fun testNudProbeFailedMetrics_Ipv4GatewayLostAfterConfirm() {
447         reachabilityMonitor.probeAll(false /* dueToRoam */)
448         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
449                 NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
450     }
451 
452     @Test
testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirmnull453     fun testNudProbeFailedMetrics_Ipv6DnsLostAfterConfirm() {
454         reachabilityMonitor.probeAll(false /* dueToRoam */)
455         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
456                 NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
457     }
458 
459     @Test
testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirmnull460     fun testNudProbeFailedMetrics_Ipv4DnsLostAfterConfirm() {
461         reachabilityMonitor.probeAll(false /* dueToRoam */)
462         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
463                 NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
464     }
465 
466     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirmnull467     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostAfterConfirm() {
468         reachabilityMonitor.probeAll(false /* dueToRoam */)
469         runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
470                 NUD_CONFIRM_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
471     }
472 
473     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirmnull474     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostAfterConfirm() {
475         reachabilityMonitor.probeAll(false /* dueToRoam */)
476         runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
477                 TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_CONFIRM_FAILED_CRITICAL, IPV6,
478                 NUD_NEIGHBOR_GATEWAY)
479     }
480 
481     @Test
testNudProbeFailedMetrics_IPv6GatewayLostOrganicnull482     fun testNudProbeFailedMetrics_IPv6GatewayLostOrganic() {
483         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
484                 NUD_ORGANIC_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
485     }
486 
487     @Test
testNudProbeFailedMetrics_IPv4GatewayLostOrganicnull488     fun testNudProbeFailedMetrics_IPv4GatewayLostOrganic() {
489         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY,
490                 NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_GATEWAY)
491     }
492 
493     @Test
testNudProbeFailedMetrics_IPv6DnsLostOrganicnull494     fun testNudProbeFailedMetrics_IPv6DnsLostOrganic() {
495         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV6_DNS,
496                 NUD_ORGANIC_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_DNS)
497     }
498 
499     @Test
testNudProbeFailedMetrics_IPv4DnsLostOrganicnull500     fun testNudProbeFailedMetrics_IPv4DnsLostOrganic() {
501         runNudProbeFailureMetricsTest(TEST_LINK_PROPERTIES, TEST_IPV4_DNS,
502                 NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_DNS)
503     }
504 
505     @Test
testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganicnull506     fun testNudProbeFailedMetrics_IPv4BothGatewayAndDnsLostOrganic() {
507         runNudProbeFailureMetricsTest(TEST_IPV4_ONLY_LINK_PROPERTIES, TEST_IPV4_GATEWAY_DNS,
508                 NUD_ORGANIC_FAILED_CRITICAL, IPV4, NUD_NEIGHBOR_BOTH)
509     }
510 
511     @Test
testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganicnull512     fun testNudProbeFailedMetrics_IPv6LinklocalScopedGatewayLostOrganic() {
513         runNudProbeFailureMetricsTest(TEST_IPV6_LINKLOCAL_SCOPED_LINK_PROPERTIES,
514                 TEST_IPV6_LINKLOCAL_SCOPED_GATEWAY, NUD_ORGANIC_FAILED_CRITICAL, IPV6,
515                 NUD_NEIGHBOR_GATEWAY)
516     }
517 
518     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoamingnull519     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostPostRoaming() {
520         reachabilityMonitor.probeAll(true /* dueToRoam */)
521         runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
522                 NUD_POST_ROAMING_FAILED, IPV6, NUD_NEIGHBOR_DNS)
523     }
524 
525     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirmnull526     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostAfterConfirm() {
527         reachabilityMonitor.probeAll(false /* dueToRoam */)
528         runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
529                 NUD_CONFIRM_FAILED, IPV6, NUD_NEIGHBOR_DNS)
530     }
531 
532     @Test
testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganicnull533     fun testNudProbeFailedMetrics_IPv6OneDnsNeighborLostOrganic() {
534         runLoseNeighborStillProvisionedTest(TEST_DUAL_LINK_PROPERTIES, TEST_IPV6_DNS,
535                 NUD_ORGANIC_FAILED, IPV6, NUD_NEIGHBOR_DNS)
536     }
537 
538     @Test
testNudProbeFailedMetrics_multipleProbesFromRoamFirstnull539     fun testNudProbeFailedMetrics_multipleProbesFromRoamFirst() {
540         reachabilityMonitor.probeAll(true /* dueToRoam */)
541         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
542         Thread.sleep(2)
543         reachabilityMonitor.probeAll(false /* dueToRoam */)
544         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
545                 NUD_POST_ROAMING_FAILED_CRITICAL)
546 
547         verifyNudFailureMetrics(NUD_POST_ROAMING_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
548     }
549 
550     @Test
testNudProbeFailedMetrics_multipleProbesFromConfirmFirstnull551     fun testNudProbeFailedMetrics_multipleProbesFromConfirmFirst() {
552         reachabilityMonitor.probeAll(false /* dueToRoam */)
553         handlerThread.waitForIdle(TEST_TIMEOUT_MS)
554         Thread.sleep(2)
555         reachabilityMonitor.probeAll(true /* dueToRoam */)
556         runLoseProvisioningTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY,
557                 NUD_CONFIRM_FAILED_CRITICAL)
558 
559         verifyNudFailureMetrics(NUD_CONFIRM_FAILED_CRITICAL, IPV6, NUD_NEIGHBOR_GATEWAY)
560     }
561 
verifyNudMacAddrChangedTypenull562     private fun verifyNudMacAddrChangedType(
563         neighbor: InetAddress,
564         eventType: NudEventType,
565         ipType: IpType
566     ) {
567         neighborMonitor.enqueuePacket(makeNewNeighMessage(neighbor, NUD_REACHABLE,
568                 "1122334455aa" /* newMac */))
569         verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(neighbor), anyString(),
570                 eq(eventType))
571         verifyNudFailureMetrics(eventType, ipType, NUD_NEIGHBOR_GATEWAY)
572     }
573 
574     @Test
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoamingnull575     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterRoaming() {
576         prepareNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
577 
578         reachabilityMonitor.probeAll(true /* dueToRoam */)
579         verifyNudMacAddrChangedType(TEST_IPV6_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV6)
580     }
581 
582     @Test
testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoamingnull583     fun testNudProbeFailedMetrics_defaultIPv4GatewayMacAddrChangedAfterRoaming() {
584         prepareNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV4_GATEWAY)
585 
586         reachabilityMonitor.probeAll(true /* dueToRoam */)
587         verifyNudMacAddrChangedType(TEST_IPV4_GATEWAY, NUD_POST_ROAMING_MAC_ADDRESS_CHANGED, IPV4)
588     }
589 
590     @Test
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirmnull591     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterConfirm() {
592         prepareNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
593 
594         reachabilityMonitor.probeAll(false /* dueToRoam */)
595         verifyNudMacAddrChangedType(TEST_IPV6_GATEWAY, NUD_CONFIRM_MAC_ADDRESS_CHANGED, IPV6)
596     }
597 
598     @Test
testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganicnull599     fun testNudProbeFailedMetrics_defaultIPv6GatewayMacAddrChangedAfterOrganic() {
600         prepareNeighborReachableButMacAddrChangedTest(TEST_LINK_PROPERTIES, TEST_IPV6_GATEWAY)
601 
602         verifyNudMacAddrChangedType(TEST_IPV6_GATEWAY, NUD_ORGANIC_MAC_ADDRESS_CHANGED, IPV6)
603     }
604 
605     @SuppressLint("NewApi")
606     @Test
testIsOnLinknull607     fun testIsOnLink() {
608         val routes: List<RouteInfo> = listOf(
609                 RouteInfo(
610                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
611                         null /* gateway */,
612                         null /* iface */,
613                         RouteInfo.RTN_THROW),
614                 RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), null /* gateway */)
615         )
616 
617         assertTrue(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
618     }
619 
620     @SuppressLint("NewApi")
621     @Test
testIsOnLink_withThrowRoutesnull622     fun testIsOnLink_withThrowRoutes() {
623         val routes: List<RouteInfo> = listOf(
624                 RouteInfo(
625                         IpPrefix(parseNumericAddress("192.168.0.0"), 16),
626                         null /* gateway */,
627                         null /* iface */,
628                         RouteInfo.RTN_THROW)
629         )
630 
631         assertFalse(IpReachabilityMonitor.isOnLink(routes, parseNumericAddress("192.168.0.1")))
632     }
633 }
634