diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 822bdf6001..859f23a141 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -26,6 +26,7 @@ import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.networkstack.tethering.UpstreamNetworkState.isVcnInterface; import android.net.INetd; import android.net.INetworkStackStatusCallback; @@ -755,6 +756,9 @@ public class IpServer extends StateMachine { // deprecation of any existing RA data. setRaParams(params); + // Be aware that updateIpv6ForwardingRules use mLastIPv6LinkProperties, so this line should + // be eariler than updateIpv6ForwardingRules. + // TODO: avoid this dependencies and move this logic into BpfCoordinator. mLastIPv6LinkProperties = v6only; updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null); @@ -892,12 +896,20 @@ public class IpServer extends StateMachine { mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex); } + private boolean isIpv6VcnNetworkInterface() { + if (mLastIPv6LinkProperties == null) return false; + + return isVcnInterface(mLastIPv6LinkProperties.getInterfaceName()); + } + // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream // changes or if a neighbor event is received. private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex, NeighborEvent e) { - // If we no longer have an upstream, clear forwarding rules and do nothing else. - if (upstreamIfindex == 0) { + // If no longer have an upstream or it is virtual network, clear forwarding rules and do + // nothing else. + // TODO: Rather than always clear rules, ensure whether ipv6 ever enable first. + if (upstreamIfindex == 0 || isIpv6VcnNetworkInterface()) { clearIpv6ForwardingRules(); return; } diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index c99007e9ad..f4a691612e 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -31,6 +31,7 @@ import static android.system.OsConstants.ETH_P_IPV6; import static com.android.networkstack.tethering.BpfUtils.DOWNSTREAM; import static com.android.networkstack.tethering.BpfUtils.UPSTREAM; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; +import static com.android.networkstack.tethering.UpstreamNetworkState.isVcnInterface; import android.app.usage.NetworkStatsManager; import android.net.INetd; @@ -677,6 +678,8 @@ public class BpfCoordinator { if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return; + if (isVcnInterface(upstreamIface)) return; + // The same interface index to name mapping may be added by different IpServer objects or // re-added by reconnection on the same upstream interface. Ignore the duplicate one. final String iface = mInterfaceNames.get(upstreamIfindex); @@ -844,9 +847,10 @@ public class BpfCoordinator { // TODO: need to consider 464xlat. if (ns != null && ns.linkProperties != null && ns.linkProperties.hasIpv4Address()) { // TODO: support ether ip upstream interface. - final InterfaceParams params = mDeps.getInterfaceParams( - ns.linkProperties.getInterfaceName()); - if (params != null && !params.hasMacAddress /* raw ip upstream only */) { + final String ifaceName = ns.linkProperties.getInterfaceName(); + final InterfaceParams params = mDeps.getInterfaceParams(ifaceName); + final boolean isVcn = isVcnInterface(ifaceName); + if (!isVcn && params != null && !params.hasMacAddress /* raw ip upstream only */) { upstreamIndex = params.index; } } @@ -890,6 +894,8 @@ public class BpfCoordinator { * TODO: consider error handling if the attach program failed. */ public void maybeAttachProgram(@NonNull String intIface, @NonNull String extIface) { + if (isVcnInterface(extIface)) return; + if (forwardingPairExists(intIface, extIface)) return; boolean firstDownstreamForThisUpstream = !isAnyForwardingPairOnUpstream(extIface); diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java index bab9f84cf7..986c3f7f0d 100644 --- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java +++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java @@ -15,6 +15,8 @@ */ package com.android.networkstack.tethering; +import static android.net.INetd.IPSEC_INTERFACE_PREFIX; + import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -48,4 +50,9 @@ public class UpstreamNetworkState { networkCapabilities == null ? "null" : networkCapabilities, linkProperties == null ? "null" : linkProperties); } + + /** Check whether the interface is VCN. */ + public static boolean isVcnInterface(@NonNull String iface) { + return iface.startsWith(IPSEC_INTERFACE_PREFIX); + } } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 378a21c1c4..6bf6a9f4ba 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -146,8 +146,10 @@ public class IpServerTest { private static final String IFACE_NAME = "testnet1"; private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE2 = "upstream1"; + private static final String IPSEC_IFACE = "ipsec0"; private static final int UPSTREAM_IFINDEX = 101; private static final int UPSTREAM_IFINDEX2 = 102; + private static final int IPSEC_IFINDEX = 103; private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; @@ -160,6 +162,8 @@ public class IpServerTest { private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams( UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); + private static final InterfaceParams IPSEC_IFACE_PARAMS = new InterfaceParams( + IPSEC_IFACE, IPSEC_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; @@ -208,6 +212,7 @@ public class IpServerTest { when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS); when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2); + when(mDependencies.getInterfaceParams(IPSEC_IFACE)).thenReturn(IPSEC_IFACE_PARAMS); mInterfaceConfiguration = new InterfaceConfigurationParcel(); mInterfaceConfiguration.flags = new String[0]; @@ -1453,4 +1458,23 @@ public class IpServerTest { public void testDadProxyUpdates_EnabledAfterR() throws Exception { checkDadProxyEnabled(true); } + + @Test + public void testSkipVirtualNetworkInBpf() throws Exception { + initTetheredStateMachine(TETHERING_BLUETOOTH, null); + final LinkProperties v6Only = new LinkProperties(); + v6Only.setInterfaceName(IPSEC_IFACE); + dispatchTetherConnectionChanged(IPSEC_IFACE, v6Only, 0); + + verify(mBpfCoordinator).maybeAttachProgram(IFACE_NAME, IPSEC_IFACE); + verify(mNetd).tetherAddForward(IFACE_NAME, IPSEC_IFACE); + verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, IPSEC_IFACE); + + final int myIfindex = TEST_IFACE_PARAMS.index; + final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1"); + final MacAddress mac = MacAddress.fromString("00:00:00:00:00:0a"); + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, mac); + verify(mBpfCoordinator, never()).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(IPSEC_IFINDEX, neigh, mac)); + } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index 32d7e5f7a6..ab542d69dd 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -1129,6 +1129,7 @@ public class BpfCoordinatorTest { final String intIface1 = "wlan1"; final String intIface2 = "rndis0"; final String extIface = "rmnet_data0"; + final String virtualIface = "ipsec0"; final BpfUtils mockMarkerBpfUtils = staticMockMarker(BpfUtils.class); final BpfCoordinator coordinator = makeBpfCoordinator(); @@ -1164,6 +1165,14 @@ public class BpfCoordinatorTest { ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface1)); ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils); ExtendedMockito.clearInvocations(mockMarkerBpfUtils); + + // [6] Skip attaching if upstream is virtual interface. + coordinator.maybeAttachProgram(intIface1, virtualIface); + ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface, DOWNSTREAM), never()); + ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM), never()); + ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils); + ExtendedMockito.clearInvocations(mockMarkerBpfUtils); + } finally { mockSession.finishMocking(); }