Add support for creating multiple ifaces with RA responders

The RA responder is needed in order to properly provision interfaces in
the ethernet tests. This CL wraps the tap interface creation and
destruction inside a small helper class.

Test: atest CtsNetTestCases:EthernetManagerTest
Change-Id: Id92a233873f2f8a738ca563f507a2ead4478aebc
This commit is contained in:
Patrick Rohr 2022-04-11 21:28:42 +02:00
commit dcfe1937d9

View file

@ -17,7 +17,9 @@ package android.net.cts
import android.Manifest.permission.MANAGE_TEST_NETWORKS
import android.Manifest.permission.NETWORK_SETTINGS
import android.net.InetAddresses
import android.net.IpConfiguration
import android.net.MacAddress
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
import android.platform.test.annotations.AppModeFull
@ -32,6 +34,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import android.content.Context
import org.junit.runner.RunWith
import kotlin.test.assertNull
import kotlin.test.fail
@ -46,10 +49,15 @@ import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_UP
import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_CLIENT
import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_NONE
import com.android.networkstack.apishim.EthernetManagerShimImpl
import com.android.testutils.RouterAdvertisementResponder
import com.android.testutils.TapPacketReader
import com.android.testutils.waitForIdle
import java.net.Inet6Address
import java.util.concurrent.Executor
import kotlin.test.assertFalse
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import java.net.NetworkInterface
private const val TIMEOUT_MS = 1000L
private const val NO_CALLBACK_TIMEOUT_MS = 200L
@ -66,9 +74,40 @@ class EthernetManagerTest {
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
private val em by lazy { EthernetManagerShimImpl.newInstance(context) }
private val createdIfaces = ArrayList<TestNetworkInterface>()
private val createdIfaces = ArrayList<EthernetTestInterface>()
private val addedListeners = ArrayList<InterfaceStateListener>()
private class EthernetTestInterface(
context: Context,
private val handler: Handler
) {
private val tapInterface: TestNetworkInterface
private val packetReader: TapPacketReader
private val raResponder: RouterAdvertisementResponder
val interfaceName get() = tapInterface.interfaceName
init {
tapInterface = runAsShell(MANAGE_TEST_NETWORKS) {
val tnm = context.getSystemService(TestNetworkManager::class.java)
tnm.createTapInterface(false /* bringUp */)
}
val mtu = NetworkInterface.getByName(tapInterface.interfaceName).getMTU()
packetReader = TapPacketReader(handler, tapInterface.fileDescriptor.fileDescriptor, mtu)
raResponder = RouterAdvertisementResponder(packetReader)
raResponder.addRouterEntry(MacAddress.fromString("01:23:45:67:89:ab"),
InetAddresses.parseNumericAddress("fe80::abcd") as Inet6Address)
packetReader.startAsyncForTest()
raResponder.start()
}
fun destroy() {
raResponder.stop()
handler.post({ packetReader.stop() })
handler.waitForIdle(TIMEOUT_MS)
}
}
private open class EthernetStateListener private constructor(
private val history: ArrayTrackRecord<CallbackEntry>
) : InterfaceStateListener,
@ -101,7 +140,7 @@ class EthernetManagerTest {
return event as T
}
fun expectCallback(iface: TestNetworkInterface, state: Int, role: Int) {
fun expectCallback(iface: EthernetTestInterface, state: Int, role: Int) {
expectCallback(InterfaceStateChanged(iface.interfaceName, state, role,
if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null))
}
@ -125,7 +164,7 @@ class EthernetManagerTest {
fun tearDown() {
setIncludeTestInterfaces(false)
for (iface in createdIfaces) {
if (iface.fileDescriptor.fileDescriptor.valid()) iface.fileDescriptor.close()
iface.destroy()
}
for (listener in addedListeners) {
em.removeInterfaceStateListener(listener)
@ -137,11 +176,8 @@ class EthernetManagerTest {
addedListeners.add(listener)
}
private fun createInterface(): TestNetworkInterface {
return runAsShell(MANAGE_TEST_NETWORKS) {
val tnm = context.getSystemService(TestNetworkManager::class.java)
tnm.createTapInterface(false /* bringUp */).also { createdIfaces.add(it) }
}
private fun createInterface(): EthernetTestInterface {
return EthernetTestInterface(context, Handler(Looper.getMainLooper()))
}
private fun setIncludeTestInterfaces(value: Boolean) {
@ -150,8 +186,8 @@ class EthernetManagerTest {
}
}
private fun removeInterface(iface: TestNetworkInterface) {
iface.fileDescriptor.close()
private fun removeInterface(iface: EthernetTestInterface) {
iface.destroy()
createdIfaces.remove(iface)
}
@ -193,15 +229,15 @@ class EthernetManagerTest {
val iface2 = createInterface()
var ifaces = em.getInterfaceList()
assertTrue(ifaces.size > 0)
assertTrue(ifaces.contains(iface1.getInterfaceName()))
assertTrue(ifaces.contains(iface2.getInterfaceName()))
assertTrue(ifaces.contains(iface1.interfaceName))
assertTrue(ifaces.contains(iface2.interfaceName))
// Remove one existing test interface and check the return list doesn't contain the
// removed interface name.
removeInterface(iface1)
ifaces = em.getInterfaceList()
assertFalse(ifaces.contains(iface1.getInterfaceName()))
assertTrue(ifaces.contains(iface2.getInterfaceName()))
assertFalse(ifaces.contains(iface1.interfaceName))
assertTrue(ifaces.contains(iface2.interfaceName))
removeInterface(iface2)
}