From eb00e3c77a658c4fa64d59dbe8d368918ad1e411 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 12 Apr 2022 16:40:37 -0700 Subject: [PATCH] Maximize VCN MTU when using IPv6 This commit maximizes VCN MTU by considering IP version. Specifically, VcnGateWayConnection stores/updates the IkeSessionConnectionInfo passed out from the IKE library during IKE setup and migration. By looking into the addresses stored in the IkeSessionConnectionInfo, VCN is able to know the IP family of the VCN tunnels. Bug: 222331693 Test: atest FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I9a2839d7827f1d6451546ec222129f286e94ae36 --- .../server/vcn/VcnGatewayConnection.java | 117 +++++++++++++++--- .../com/android/server/vcn/util/MtuUtils.java | 27 +++- ...cnGatewayConnectionConnectedStateTest.java | 15 ++- .../server/vcn/VcnGatewayConnectionTest.java | 6 +- .../vcn/VcnGatewayConnectionTestBase.java | 16 +++ .../android/server/vcn/util/MtuUtilsTest.java | 93 +++++++++++--- 6 files changed, 236 insertions(+), 38 deletions(-) diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index cefd8efe96580..05df22f124eda 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -61,6 +61,7 @@ import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; @@ -509,6 +510,42 @@ public class VcnGatewayConnection extends StateMachine { } } + /** + * Sent when an IKE session connection information has changed. + * + *

This signal is always fired before EVENT_SETUP_COMPLETED and EVENT_MIGRATION_COMPLETED. + * + *

Only relevant in the Connecting and Connected state. + * + * @param arg1 The session token for the IKE Session whose connection information has changed, + * used to prevent out-of-date signals from propagating. + * @param obj @NonNull An EventIkeConnectionInfoChangedInfo instance with relevant data. + */ + private static final int EVENT_IKE_CONNECTION_INFO_CHANGED = 12; + + private static class EventIkeConnectionInfoChangedInfo implements EventInfo { + @NonNull public final IkeSessionConnectionInfo ikeConnectionInfo; + + EventIkeConnectionInfoChangedInfo(@NonNull IkeSessionConnectionInfo ikeConnectionInfo) { + this.ikeConnectionInfo = ikeConnectionInfo; + } + + @Override + public int hashCode() { + return Objects.hash(ikeConnectionInfo); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof EventIkeConnectionInfoChangedInfo)) { + return false; + } + + final EventIkeConnectionInfoChangedInfo rhs = (EventIkeConnectionInfoChangedInfo) other; + return Objects.equals(ikeConnectionInfo, rhs.ikeConnectionInfo); + } + } + @VisibleForTesting(visibility = Visibility.PRIVATE) @NonNull final DisconnectedState mDisconnectedState = new DisconnectedState(); @@ -623,6 +660,14 @@ public class VcnGatewayConnection extends StateMachine { */ private UnderlyingNetworkRecord mUnderlying; + /** + * The current IKE Session connection information + * + *

Set in Connected and Migrating states, always @NonNull in Connected, Migrating + * states, @Nullable otherwise. + */ + private IkeSessionConnectionInfo mIkeConnectionInfo; + /** * The active IKE session. * @@ -1197,6 +1242,14 @@ public class VcnGatewayConnection extends StateMachine { exceptionMessage); } + private void ikeConnectionInfoChanged( + int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { + sendMessageAndAcquireWakeLock( + EVENT_IKE_CONNECTION_INFO_CHANGED, + token, + new EventIkeConnectionInfoChangedInfo(ikeConnectionInfo)); + } + private void sessionClosed(int token, @Nullable Exception exception) { if (exception != null) { notifyStatusCallbackForSessionClosed(exception); @@ -1313,7 +1366,8 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough - case EVENT_MIGRATION_COMPLETED: + case EVENT_MIGRATION_COMPLETED: // Fallthrough + case EVENT_IKE_CONNECTION_INFO_CHANGED: logUnexpectedEvent(msg.what); break; default: @@ -1592,6 +1646,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mDisconnectingState); break; case EVENT_SETUP_COMPLETED: // fallthrough + case EVENT_IKE_CONNECTION_INFO_CHANGED: // fallthrough case EVENT_TRANSFORM_CREATED: // Child setup complete; move to ConnectedState for NetworkAgent registration deferMessage(msg); @@ -1614,12 +1669,17 @@ public class VcnGatewayConnection extends StateMachine { protected void updateNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnNetworkAgent agent, - @NonNull VcnChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( - mConnectionConfig, tunnelIface, childConfig, mUnderlying); + mConnectionConfig, + tunnelIface, + childConfig, + mUnderlying, + ikeConnectionInfo); agent.sendNetworkCapabilities(caps); agent.sendLinkProperties(lp); @@ -1630,12 +1690,17 @@ public class VcnGatewayConnection extends StateMachine { protected VcnNetworkAgent buildNetworkAgent( @NonNull IpSecTunnelInterface tunnelIface, - @NonNull VcnChildSessionConfiguration childConfig) { + @NonNull VcnChildSessionConfiguration childConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final NetworkCapabilities caps = buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled); final LinkProperties lp = buildConnectedLinkProperties( - mConnectionConfig, tunnelIface, childConfig, mUnderlying); + mConnectionConfig, + tunnelIface, + childConfig, + mUnderlying, + ikeConnectionInfo); final NetworkAgentConfig nac = new NetworkAgentConfig.Builder() .setLegacyType(ConnectivityManager.TYPE_MOBILE) @@ -1838,7 +1903,11 @@ public class VcnGatewayConnection extends StateMachine { mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig; setupInterfaceAndNetworkAgent( - mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig); + mCurrentToken, + mTunnelIface, + mChildConfig, + oldChildConfig, + mIkeConnectionInfo); break; case EVENT_DISCONNECT_REQUESTED: handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); @@ -1852,6 +1921,10 @@ public class VcnGatewayConnection extends StateMachine { handleMigrationCompleted(migrationCompletedInfo); break; + case EVENT_IKE_CONNECTION_INFO_CHANGED: + mIkeConnectionInfo = + ((EventIkeConnectionInfoChangedInfo) msg.obj).ikeConnectionInfo; + break; default: logUnhandledMessage(msg); break; @@ -1875,7 +1948,7 @@ public class VcnGatewayConnection extends StateMachine { migrationCompletedInfo.outTransform, IpSecManager.DIRECTION_OUT); - updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo); // Trigger re-validation after migration events. mConnectivityManager.reportNetworkConnectivity( @@ -1906,7 +1979,8 @@ public class VcnGatewayConnection extends StateMachine { // Network not yet set up, or child not yet connected. if (mNetworkAgent != null && mChildConfig != null) { // If only network properties changed and agent is active, update properties - updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + updateNetworkAgent( + mTunnelIface, mNetworkAgent, mChildConfig, mIkeConnectionInfo); } } } @@ -1915,13 +1989,14 @@ public class VcnGatewayConnection extends StateMachine { int token, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, - @NonNull VcnChildSessionConfiguration oldChildConfig) { + @NonNull VcnChildSessionConfiguration oldChildConfig, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { setupInterface(token, tunnelIface, childConfig, oldChildConfig); if (mNetworkAgent == null) { - mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig); + mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig, ikeConnectionInfo); } else { - updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig); + updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig, ikeConnectionInfo); // mNetworkAgent not null, so the VCN Network has already been established. Clear // the failed attempt counter and safe mode alarm since this transition is complete. @@ -2098,7 +2173,8 @@ public class VcnGatewayConnection extends StateMachine { @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, - @Nullable UnderlyingNetworkRecord underlying) { + @Nullable UnderlyingNetworkRecord underlying, + @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { final IkeTunnelConnectionParams ikeTunnelParams = gatewayConnectionConfig.getTunnelConnectionParams(); final LinkProperties lp = new LinkProperties(); @@ -2139,7 +2215,8 @@ public class VcnGatewayConnection extends StateMachine { MtuUtils.getMtu( ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(), gatewayConnectionConfig.getMaxMtu(), - underlyingMtu)); + underlyingMtu, + ikeConnectionInfo.getLocalAddress() instanceof Inet4Address)); return lp; } @@ -2154,7 +2231,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { logDbg("IkeOpened for token " + mToken); - // Nothing to do here. + ikeConnectionInfoChanged(mToken, ikeSessionConfig.getIkeSessionConnectionInfo()); } @Override @@ -2174,6 +2251,13 @@ public class VcnGatewayConnection extends StateMachine { logInfo("IkeError for token " + mToken, exception); // Non-fatal, log and continue. } + + @Override + public void onIkeSessionConnectionInfoChanged( + @NonNull IkeSessionConnectionInfo connectionInfo) { + logDbg("onIkeSessionConnectionInfoChanged for token " + mToken); + ikeConnectionInfoChanged(mToken, connectionInfo); + } } /** Implementation of ChildSessionCallback, exposed for testing. */ @@ -2349,6 +2433,11 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = record; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + IkeSessionConnectionInfo getIkeConnectionInfo() { + return mIkeConnectionInfo; + } + @VisibleForTesting(visibility = Visibility.PRIVATE) boolean isQuitting() { return mIsQuitting.getValue(); diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java index 5d40cca3e19db..356c71f5f26a8 100644 --- a/services/core/java/com/android/server/vcn/util/MtuUtils.java +++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java @@ -51,9 +51,20 @@ public class MtuUtils { /** * Max ESP overhead possible * - *

60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader) + *

60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next + * Header). Note: Payload data, Pad Length and Next Header will need to be padded to be multiple + * of the block size of a cipher, and at the same time be aligned on a 4-byte boundary. */ - private static final int GENERIC_ESP_OVERHEAD_MAX = 78; + private static final int GENERIC_ESP_OVERHEAD_MAX_V4 = 78; + + /** + * Max ESP overhead possible + * + *

40 (Outer IPv6) + 4 (SPI) + 4 (Seq) + 2 (Pad Length + Next Header). Note: Payload data, + * Pad Length and Next Header will need to be padded to be multiple of the block size of a + * cipher, and at the same time be aligned on a 4-byte boundary. + */ + private static final int GENERIC_ESP_OVERHEAD_MAX_V6 = 50; /** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */ private static final Map AUTH_ALGORITHM_OVERHEAD; @@ -108,7 +119,10 @@ public class MtuUtils { * */ public static int getMtu( - @NonNull List childProposals, int maxMtu, int underlyingMtu) { + @NonNull List childProposals, + int maxMtu, + int underlyingMtu, + boolean isIpv4) { if (underlyingMtu <= 0) { return IPV6_MIN_MTU; } @@ -145,10 +159,13 @@ public class MtuUtils { } } + final int genericEspOverheadMax = + isIpv4 ? GENERIC_ESP_OVERHEAD_MAX_V4 : GENERIC_ESP_OVERHEAD_MAX_V6; + // Return minimum of maxMtu, and the adjusted MTUs based on algorithms. - final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX; + final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - genericEspOverheadMax; final int normalModeMtu = - underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX; + underlyingMtu - maxCryptOverhead - maxAuthOverhead - genericEspOverheadMax; return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu); } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 841b81c2a282c..15d4f1097108f 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -56,6 +56,7 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -216,14 +217,23 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testMigration() throws Exception { triggerChildOpened(); + mTestLooper.dispatchAll(); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); mGatewayConnection .getUnderlyingNetworkControllerCallback() .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2); + + final IkeSessionConnectionInfo newIkeConnectionInfo = + new IkeSessionConnectionInfo( + TEST_ADDR_V4, TEST_ADDR_V4_2, TEST_UNDERLYING_NETWORK_RECORD_2.network); + getIkeSessionCallback().onIkeSessionConnectionInfoChanged(newIkeConnectionInfo); getChildSessionCallback() .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); + assertEquals(newIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); + verify(mIpSecSvc, times(2)) .setNetworkForTunnelInterface( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), @@ -246,7 +256,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection MtuUtils.getMtu( saProposals, mConfig.getMaxMtu(), - TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu()); + TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu(), + true /* isIpv4 */); verify(mNetworkAgent).sendLinkProperties( argThat(lp -> expectedMtu == lp.getMtu() && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); @@ -269,6 +280,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .when(mMockChildSessionConfig) .getInternalDnsServers(); + getIkeSessionCallback().onOpened(mIkeSessionConfiguration); getChildSessionCallback().onOpened(mMockChildSessionConfig); } @@ -298,6 +310,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); + assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo()); final ArgumentCaptor lpCaptor = ArgumentCaptor.forClass(LinkProperties.class); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index b9dfda38a01c2..6a9a1e22cab11 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -213,7 +213,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { VcnGatewayConnectionConfigTest.buildTestConfig(), tunnelIface, childSessionConfig, - record); + record, + mIkeConnectionInfo); verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); @@ -226,7 +227,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { VcnGatewayConnectionConfigTest.buildTestConfig(), tunnelIface, childSessionConfig, - record); + record, + mIkeConnectionInfo); verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 5628321b59757..3d95a9b32d4a4 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -47,6 +47,8 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.IkeSessionCallback; +import android.net.ipsec.ike.IkeSessionConfiguration; +import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; @@ -80,6 +82,13 @@ public class VcnGatewayConnectionTestBase { doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid(); } + protected static final InetAddress TEST_ADDR = InetAddresses.parseNumericAddress("2001:db8::1"); + protected static final InetAddress TEST_ADDR_2 = + InetAddresses.parseNumericAddress("2001:db8::2"); + protected static final InetAddress TEST_ADDR_V4 = + InetAddresses.parseNumericAddress("192.0.2.1"); + protected static final InetAddress TEST_ADDR_V4_2 = + InetAddresses.parseNumericAddress("192.0.2.2"); protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); protected static final InetAddress TEST_DNS_ADDR_2 = @@ -148,6 +157,9 @@ public class VcnGatewayConnectionTestBase { @NonNull protected final IpSecService mIpSecSvc; @NonNull protected final ConnectivityManager mConnMgr; + @NonNull protected final IkeSessionConnectionInfo mIkeConnectionInfo; + @NonNull protected final IkeSessionConfiguration mIkeSessionConfiguration; + protected VcnIkeSession mMockIkeSession; protected VcnGatewayConnection mGatewayConnection; @@ -173,6 +185,10 @@ public class VcnGatewayConnectionTestBase { VcnTestUtils.setupSystemService( mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + mIkeConnectionInfo = + new IkeSessionConnectionInfo(TEST_ADDR, TEST_ADDR_2, mock(Network.class)); + mIkeSessionConfiguration = new IkeSessionConfiguration.Builder(mIkeConnectionInfo).build(); + doReturn(mContext).when(mVcnContext).getContext(); doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); diff --git a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java index 29511f780bf61..e9e70783ebe90 100644 --- a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java +++ b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java @@ -46,34 +46,85 @@ import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class MtuUtilsTest { - @Test - public void testUnderlyingMtuZero() { + private void verifyUnderlyingMtuZero(boolean isIpv4) { assertEquals( - IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */)); + IPV6_MIN_MTU, + getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */, isIpv4)); } @Test - public void testClampsToMaxMtu() { - assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */)); + public void testUnderlyingMtuZeroV4() { + verifyUnderlyingMtuZero(true /* isIpv4 */); } @Test - public void testNormalModeAlgorithmLessThanUnderlyingMtu() { - final List saProposals = - Arrays.asList( - new ChildSaProposal.Builder() - .addEncryptionAlgorithm( - ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256) - .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) - .build()); + public void testUnderlyingMtuZeroV6() { + verifyUnderlyingMtuZero(false /* isIpv4 */); + } + private void verifyClampsToMaxMtu(boolean isIpv4) { + assertEquals( + 0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */, isIpv4)); + } + + @Test + public void testClampsToMaxMtuV4() { + verifyClampsToMaxMtu(true /* isIpv4 */); + } + + @Test + public void testClampsToMaxMtuV6() { + verifyClampsToMaxMtu(false /* isIpv4 */); + } + + private List buildChildSaProposalsWithNormalModeAlgo() { + return Arrays.asList( + new ChildSaProposal.Builder() + .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256) + .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .build()); + } + + private void verifyNormalModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) { final int actualMtu = - getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + isIpv4); assertTrue(ETHER_MTU > actualMtu); } @Test - public void testCombinedModeAlgorithmLessThanUnderlyingMtu() { + public void testNormalModeAlgorithmLessThanUnderlyingMtuV4() { + verifyNormalModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */); + } + + @Test + public void testNormalModeAlgorithmLessThanUnderlyingMtuV6() { + verifyNormalModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */); + } + + @Test + public void testMtuIpv4LessThanMtuIpv6() { + final int actualMtuV4 = + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + true /* isIpv4 */); + + final int actualMtuV6 = + getMtu( + buildChildSaProposalsWithNormalModeAlgo(), + ETHER_MTU /* maxMtu */, + ETHER_MTU /* underlyingMtu */, + false /* isIpv4 */); + + assertTrue(actualMtuV4 < actualMtuV6); + } + + private void verifyCombinedModeAlgorithmLessThanUnderlyingMtu(boolean isIpv4) { final List saProposals = Arrays.asList( new ChildSaProposal.Builder() @@ -86,7 +137,17 @@ public class MtuUtilsTest { .build()); final int actualMtu = - getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */); + getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */, isIpv4); assertTrue(ETHER_MTU > actualMtu); } + + @Test + public void testCombinedModeAlgorithmLessThanUnderlyingMtuV4() { + verifyCombinedModeAlgorithmLessThanUnderlyingMtu(true /* isIpv4 */); + } + + @Test + public void testCombinedModeAlgorithmLessThanUnderlyingMtuV6() { + verifyCombinedModeAlgorithmLessThanUnderlyingMtu(false /* isIpv4 */); + } }