Migrate NetdUtils from networkAddRoute to networkAddRouteParcel.

This will allow us to deprecate networkAddRoute.

Bug:412629841
Test: atest TetheringTests
Flag: EXEMPT Using device config kill-switch
Change-Id: I20e988f760b8ad22b51effdc1f0e204763c6e240
This commit is contained in:
Sarup Dalwani 2025-07-02 17:25:59 +00:00
commit 98e5827ccc
6 changed files with 184 additions and 79 deletions

View file

@ -39,6 +39,7 @@ import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.util.NetworkConstants.asByte;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.net.module.util.ConnectivityCommonFlags.USE_ROUTE_PARCEL_IPCS;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.networkstack.tethering.TetheringConfiguration.USE_SYNC_SM;
@ -232,6 +233,13 @@ public class IpServer extends StateMachineShim {
return Flags.tetheringAndP2pGoLocalAgent();
}
/**
* @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
*/
public boolean isFeatureNotChickenedOut(Context context, String name) {
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name);
}
/** Create a NetworkAgent instance to be used by IpServer. */
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SuppressLint("NewApi")
@ -296,6 +304,7 @@ public class IpServer extends StateMachineShim {
private final boolean mUsingLegacyDhcp;
private final int mP2pLeasesSubnetPrefixLength;
private final boolean mIsWifiP2pDedicatedIpEnabled;
private final boolean mUseRouteParcel;
private final Dependencies mDeps;
@ -400,6 +409,11 @@ public class IpServer extends StateMachineShim {
TETHERING_AND_P2P_GO_LOCAL_AGENT)
: mDeps.isTetheringAndP2pGoLocalAgentBetaFlagEnabled());
// For post 25Q2 releases always use *RouteParcel methods. For 25Q2 or lower, decide based
// on kill-switch
mUseRouteParcel = SdkUtil.isAtLeast25Q4()
|| mDeps.isFeatureNotChickenedOut(mContext, USE_ROUTE_PARCEL_IPCS);
mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState();
mTetheredState = new TetheredState();
@ -919,7 +933,8 @@ public class IpServer extends StateMachineShim {
}
private void removeRoutesFromNetwork(int netId, @NonNull final List<RouteInfo> toBeRemoved) {
final int removalFailures = NetdUtils.removeRoutesFromNetwork(mNetd, netId, toBeRemoved);
final int removalFailures = NetdUtils.removeRoutesFromNetwork(mNetd, netId, toBeRemoved,
mUseRouteParcel);
if (removalFailures > 0) {
mLog.e("Failed to remove " + removalFailures
+ " IPv6 routes from network " + netId + ".");
@ -950,15 +965,14 @@ public class IpServer extends StateMachineShim {
}
}
private void addRoutesToNetwork(int netId,
@NonNull final List<RouteInfo> toBeAdded) {
private void addRoutesToNetwork(int netId, @NonNull final List<RouteInfo> toBeAdded) {
// It's safe to call addInterfaceToNetwork() even if
// the interface is already in the network.
addInterfaceToNetwork(netId, mIfaceName);
try {
// Add routes from local network. Note that adding routes that
// already exist does not cause an error (EEXIST is silently ignored).
NetdUtils.addRoutesToNetwork(mNetd, netId, mIfaceName, toBeAdded);
NetdUtils.addRoutesToNetwork(mNetd, netId, mIfaceName, toBeAdded, mUseRouteParcel);
} catch (IllegalStateException e) {
mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
return;
@ -972,6 +986,7 @@ public class IpServer extends StateMachineShim {
final List<RouteInfo> routesToBeRemoved =
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
if (mTetheringAgent == null) {
// Routes for local network are not considered local routes.
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
}
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
@ -1219,10 +1234,11 @@ public class IpServer extends StateMachineShim {
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
// Activate a route to dest and IPv6 link local.
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName, RTN_UNICAST));
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName,
RTN_UNICAST), mUseRouteParcel);
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
RTN_UNICAST));
RTN_UNICAST), mUseRouteParcel);
}
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
mLog.e("Error Tethering", e);
@ -1352,6 +1368,7 @@ public class IpServer extends StateMachineShim {
final List<RouteInfo> routesToBeRemoved =
List.of(getDirectConnectedRoute(deprecatedLinkAddress));
if (mTetheringAgent == null) {
// Routes for local network are not considered local routes.
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
}
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);

View file

@ -39,6 +39,7 @@ import static android.net.ip.IpServer.getTetherableIpv6Prefixes;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.modules.utils.build.SdkLevel.isAtLeastV;
import static com.android.net.module.util.ConnectivityCommonFlags.USE_ROUTE_PARCEL_IPCS;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
@ -234,6 +235,9 @@ public class IpServerTest {
eq(TETHERING_AND_P2P_GO_LOCAL_AGENT));
doReturn(agentFeatureEnabled).when(mDependencies)
.isTetheringAndP2pGoLocalAgentBetaFlagEnabled();
doAnswer(
invocation -> mFeatureFlags.getOrDefault((String) invocation.getArgument(1), true)
).when(mDependencies).isFeatureNotChickenedOut(any(), anyString());
if (isAtLeastV()) {
when(mDependencies.makeNetworkAgent(any(), any(), anyString(), anyInt(), any()))
.thenReturn(mNetworkAgent);
@ -385,6 +389,7 @@ public class IpServerTest {
}
@Test
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
public void canBeTetheredAsBluetooth() throws Exception {
initStateMachine(TETHERING_BLUETOOTH);
@ -404,13 +409,11 @@ public class IpServerTest {
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
if (isTetheringNetworkAgentFeatureEnabled()) {
inOrder.verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
inOrder.verify(mNetd, never())
.networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute(inOrder);
} else {
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2))
.networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), any(), any());
verifyNetworkAddRoute(inOrder, true, 2);
}
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
@ -451,6 +454,7 @@ public class IpServerTest {
}
@Test
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
public void canBeTetheredAsUsb() throws Exception {
initStateMachine(TETHERING_USB);
@ -465,12 +469,10 @@ public class IpServerTest {
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
if (isTetheringNetworkAgentFeatureEnabled()) {
inOrder.verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
inOrder.verify(mNetd, never())
.networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute(inOrder);
} else {
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(2))
.networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), any(), any());
verifyNetworkAddRoute(inOrder, true, 2);
}
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
@ -481,6 +483,7 @@ public class IpServerTest {
}
@Test
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
public void canBeTetheredAsWifiP2p_NotUsingDedicatedIp() throws Exception {
initStateMachine(TETHERING_WIFI_P2P);
@ -494,8 +497,7 @@ public class IpServerTest {
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
any(), any());
verifyNetworkAddRoute(inOrder, true, 2);
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
@ -505,6 +507,7 @@ public class IpServerTest {
}
@Test
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
public void canBeTetheredAsWifiP2p_UsingDedicatedIp() throws Exception {
initStateMachine(TETHERING_WIFI_P2P, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD,
true /* shouldEnableWifiP2pDedicatedIp */);
@ -521,8 +524,7 @@ public class IpServerTest {
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
any(), any());
verifyNetworkAddRoute(inOrder, true, 2);
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
@ -789,6 +791,7 @@ public class IpServerTest {
}
@Test
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
public void testOnNewPrefixRequest() throws Exception {
initStateMachine(TETHERING_NCM);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, 0, 0,
@ -810,8 +813,7 @@ public class IpServerTest {
inOrder.verify(mRoutingCoordinatorManager, never()).requestDownstreamAddress(any());
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
any(), any());
verifyNetworkAddRoute(inOrder, true, 2);
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
@ -1120,24 +1122,67 @@ public class IpServerTest {
return true;
}
@FeatureFlag(name = Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT)
private void verifyNeverNetworkAddRoute(InOrder inOrder) throws Exception {
inOrder.verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(),
anyString());
}
private void verifyNetworkAddRoute(InOrder inOrder, boolean useParcelMethods, int times)
throws Exception {
if (useParcelMethods) {
inOrder.verify(mNetd, times(times)).networkAddRouteParcel(eq(INetd.LOCAL_NET_ID),
argThat(routeInfo -> routeInfo != null && IFACE_NAME.equals(routeInfo.ifName)));
inOrder.verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(),
anyString());
} else {
inOrder.verify(mNetd, times(times)).networkAddRoute(eq(INetd.LOCAL_NET_ID),
eq(IFACE_NAME), any(), any());
inOrder.verify(mNetd, never()).networkAddRouteParcel(anyInt(), any());
}
}
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@FeatureFlag(name = Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT)
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
@Test
public void testTetheringNetworkAgent_tetheringAgentEnabled() throws Exception {
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, true);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, true);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, true, true);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, true, true);
}
@FeatureFlag(name = Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, enabled = false)
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS)
@Test
public void testTetheringNetworkAgent_tetheringAgentDisabled() throws Exception {
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, false);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, false);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, false, true);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, false, true);
}
private void doTestTetheringNetworkAgent(int scope, boolean expectAgentEnabled)
// todo(b/441359615) : remove the test while cleaning up flag USE_ROUTE_PARCEL_IPCS.
@IgnoreAfter(Build.VERSION_CODES.BAKLAVA)
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS, enabled = false)
@Test
public void testTetheringNetworkAgent_UseRouteParcelDisabled_RouteMethodsCalled()
throws Exception {
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, false, false);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, false, false);
}
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
@FeatureFlag(name = USE_ROUTE_PARCEL_IPCS, enabled = false)
@Test
public void testTetheringNetworkAgent_postBaklava_RouteParcelMethodsCalled()
throws Exception {
// On Android versions post-Baklava, the implementation exclusively uses route parcel
// IPCs. As a result, the USE_ROUTE_PARCEL_IPCS feature flag is no longer checked and
// has no effect.
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_GLOBAL, false, true);
doTestTetheringNetworkAgent(CONNECTIVITY_SCOPE_LOCAL, false, true);
}
private void doTestTetheringNetworkAgent(int scope, boolean expectAgentEnabled,
boolean useRouteParcelIpcs) throws Exception {
initStateMachine(TETHERING_USB);
final InOrder inOrder = inOrder(mNetworkAgent, mNetd);
@ -1148,12 +1193,12 @@ public class IpServerTest {
inOrder.verify(mNetd, times(1)).tetherInterfaceAdd(anyString());
if (expectAgentEnabled) {
inOrder.verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
inOrder.verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), any(), any());
verifyNeverNetworkAddRoute(inOrder);
inOrder.verify(mNetworkAgent, times(1)).sendLinkProperties(any());
inOrder.verify(mNetworkAgent, times(1)).markConnected();
} else {
inOrder.verify(mNetd, times(1)).networkAddInterface(anyInt(), anyString());
inOrder.verify(mNetd, times(2)).networkAddRoute(anyInt(), anyString(), any(), any());
verifyNetworkAddRoute(inOrder, useRouteParcelIpcs, 2);
inOrder.verify(mNetworkAgent, never()).sendLinkProperties(any());
inOrder.verify(mNetworkAgent, never()).markConnected();
}
@ -1226,7 +1271,7 @@ public class IpServerTest {
inOrder.verify(mNetworkAgent).register();
inOrder.verify(mNetd, never()).networkCreate(any());
inOrder.verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), any(), any());
verifyNeverNetworkAddRoute(inOrder);
// Ipv6 link local route won't show up in the LinkProperties, so just
// verify ipv4 route.
@ -1249,7 +1294,7 @@ public class IpServerTest {
lp.setInterfaceName(UPSTREAM_IFACE);
lp.setLinkAddresses(UPSTREAM_ADDRESSES);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
inOrder.verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), any(), any());
verifyNeverNetworkAddRoute(inOrder);
inOrder.verify(mNetworkAgent).sendLinkProperties(lpCaptor.capture());
// Expect one Ipv4 route, plus one Ipv6 route.

View file

@ -77,6 +77,7 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.modules.utils.build.SdkLevel.isAtLeastV;
import static com.android.net.module.util.ConnectivityCommonFlags.USE_ROUTE_PARCEL_IPCS;
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
@ -211,6 +212,7 @@ import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.PrivateAddressCoordinator;
import com.android.net.module.util.RoutingCoordinatorManager;
import com.android.net.module.util.RoutingCoordinatorService;
import com.android.net.module.util.SdkUtil;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.ip.IpNeighborMonitor;
import com.android.networkstack.apishim.common.BluetoothPanShim;
@ -494,6 +496,11 @@ public class TetheringTest {
public boolean isTetheringAndP2pGoLocalAgentBetaFlagEnabled() {
return mFeatureFlags.getOrDefault(Flags.FLAG_TETHERING_AND_P2P_GO_LOCAL_AGENT, false);
}
@Override
public boolean isFeatureNotChickenedOut(Context context, String name) {
return mFeatureFlags.getOrDefault(name, true);
}
}
public class MockTetheringDependencies extends TetheringDependencies {
@ -994,11 +1001,10 @@ public class TetheringTest {
verify(mNetd).tetherInterfaceAdd(ifname);
if (expectAgentEnabled) {
verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute();
} else {
verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, ifname);
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname),
anyString(), anyString());
verifyNetworkAddRoute(ifname, 2);
}
}
@ -2250,11 +2256,10 @@ public class TetheringTest {
verify(mNetd, times(1)).tetherInterfaceAdd(TEST_WLAN_IFNAME);
if (isTetheringNetworkAgentFeatureEnabled()) {
verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute();
} else {
verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
anyString(), anyString());
verifyNetworkAddRoute(TEST_WLAN_IFNAME, 2);
}
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
@ -4183,19 +4188,17 @@ public class TetheringTest {
verify(mNetd).tetherInterfaceAdd(TEST_BT_IFNAME);
if (isTetheringNetworkAgentFeatureEnabled()) {
verify(mNetd, never()).networkAddInterface(anyInt(), anyString());
verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute();
} else {
verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, TEST_BT_IFNAME);
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_BT_IFNAME),
anyString(), anyString());
verifyNetworkAddRoute(TEST_BT_IFNAME, 2);
}
verify(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
verify(mNetd).tetherStartWithConfiguration(any());
if (isTetheringNetworkAgentFeatureEnabled()) {
verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verifyNeverNetworkAddRoute();
} else {
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_BT_IFNAME),
anyString(), anyString());
verifyNetworkAddRoute(TEST_BT_IFNAME, 2);
}
verifyNoMoreInteractions(mNetd);
reset(mNetd);
@ -4208,6 +4211,29 @@ public class TetheringTest {
return false;
}
private void verifyNeverNetworkAddRoute() throws Exception {
verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), anyString(), anyString());
verify(mNetd, never()).networkAddRouteParcel(anyInt(), any());
}
private boolean useRouteParcelIpcs() {
return SdkUtil.isAtLeast25Q4()
|| mFeatureFlags.getOrDefault(USE_ROUTE_PARCEL_IPCS, true);
}
private void verifyNetworkAddRoute(String ifName, int times)
throws Exception {
if (useRouteParcelIpcs()) {
verify(mNetd, times(times))
.networkAddRouteParcel(eq(INetd.LOCAL_NET_ID),
argThat((parcel) -> ifName.equals(parcel.ifName)));
} else {
verify(mNetd, times(times))
.networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifName),
anyString(), anyString());
}
}
private void verifyNetdCommandForBtTearDown() throws Exception {
verify(mNetd).tetherApplyDnsInterfaces();
verify(mNetd).tetherInterfaceRemove(TEST_BT_IFNAME);

View file

@ -176,27 +176,27 @@ public class NetdUtils {
/** Add |routes| to the given network. */
public static void addRoutesToNetwork(final INetd netd, int netId, final String iface,
final List<RouteInfo> routes) {
final List<RouteInfo> routes, final boolean useRouteParcel) {
for (RouteInfo route : routes) {
if (!route.isDefaultRoute()) {
modifyRoute(netd, ModifyOperation.ADD, netId, route);
modifyRoute(netd, ModifyOperation.ADD, netId, route, useRouteParcel);
}
}
// IPv6 link local should be activated always.
modifyRoute(netd, ModifyOperation.ADD, netId,
new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST));
new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST), useRouteParcel);
}
/** Remove routes from the given network. */
public static int removeRoutesFromNetwork(final INetd netd, int netId,
final List<RouteInfo> routes) {
final List<RouteInfo> routes, final boolean useRouteParcel) {
int failures = 0;
for (RouteInfo route : routes) {
try {
modifyRoute(netd, ModifyOperation.REMOVE, netId, route);
modifyRoute(netd, ModifyOperation.REMOVE, netId, route, useRouteParcel);
} catch (IllegalStateException e) {
failures++;
}
@ -231,18 +231,26 @@ public class NetdUtils {
/** Add or remove |route|. */
public static void modifyRoute(final INetd netd, final ModifyOperation op, final int netId,
final RouteInfo route) {
final String ifName = route.getInterface();
final String dst = route.getDestination().toString();
final String nextHop = findNextHop(route);
final RouteInfo route, final boolean useRouteParcel) {
try {
switch(op) {
case ADD:
netd.networkAddRoute(netId, ifName, dst, nextHop);
if (useRouteParcel) {
RouteInfoParcel routeParcel = NetdUtils.toRouteInfoParcel(route);
netd.networkAddRouteParcel(netId, routeParcel);
} else {
netd.networkAddRoute(netId, route.getInterface(),
route.getDestination().toString(), findNextHop(route));
}
break;
case REMOVE:
netd.networkRemoveRoute(netId, ifName, dst, nextHop);
if (useRouteParcel) {
RouteInfoParcel routeParcel = NetdUtils.toRouteInfoParcel(route);
netd.networkRemoveRouteParcel(netId, routeParcel);
} else {
netd.networkRemoveRoute(netId, route.getInterface(),
route.getDestination().toString(), findNextHop(route));
}
break;
default:
throw new IllegalStateException("Unsupported modify operation:" + op);
@ -256,31 +264,10 @@ public class NetdUtils {
* Convert a RouteInfo into a RouteInfoParcel.
*/
public static RouteInfoParcel toRouteInfoParcel(RouteInfo route) {
final String nextHop;
switch (route.getType()) {
case RouteInfo.RTN_UNICAST:
if (route.hasGateway()) {
nextHop = route.getGateway().getHostAddress();
} else {
nextHop = INetd.NEXTHOP_NONE;
}
break;
case RouteInfo.RTN_UNREACHABLE:
nextHop = INetd.NEXTHOP_UNREACHABLE;
break;
case RouteInfo.RTN_THROW:
nextHop = INetd.NEXTHOP_THROW;
break;
default:
nextHop = INetd.NEXTHOP_NONE;
break;
}
final RouteInfoParcel rip = new RouteInfoParcel();
rip.ifName = route.getInterface();
rip.destination = route.getDestination().toString();
rip.nextHop = nextHop;
rip.nextHop = findNextHop(route);
rip.mtu = route.getMtu();
return rip;

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.net.module.util;
/**
* Collection of flag constants shared across modules.
* @hide
*/
public class ConnectivityCommonFlags {
/**
* A feature flag to use the network{Add,Remove}RouteParcel netd IPCs instead of the legacy
* network{Add,Remote}Route IPCs. This flag is used by both the connectivity and wifi modules.
*/
public static final String USE_ROUTE_PARCEL_IPCS = "use_route_parcel_ipcs";
}

View file

@ -189,6 +189,7 @@ import static com.android.testutils.MiscAsserts.assertLength;
import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
import static com.android.testutils.MiscAsserts.assertSameElements;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import static com.android.testutils.TestableNetworkCallback.Event.AVAILABLE;
import static com.android.testutils.TestableNetworkCallback.Event.BLOCKED_STATUS;
import static com.android.testutils.TestableNetworkCallback.Event.BLOCKED_STATUS_INT;
@ -199,7 +200,6 @@ import static com.android.testutils.TestableNetworkCallback.Event.NETWORK_CAPS_U
import static com.android.testutils.TestableNetworkCallback.Event.RESUMED;
import static com.android.testutils.TestableNetworkCallback.Event.SUSPENDED;
import static com.android.testutils.TestableNetworkCallback.Event.UNAVAILABLE;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;