Track NAT64 in the framework and start clatd iff NAT64 detected

Currently, both netd and clatd do NAT64 prefix detection, and we
start clatd on all IPv6-only networks regardless of whether netd
has detected a NAT64 prefix or not.

Instead, track the NAT64 prefix in the framework, and only start
clatd if the prefix is detected. This will allow us to remove
DNS64 detection in clatd, and pass the NAT64 prefix and the IPv6
address to clatd on the command line instead of clatd finding it
itself. That way, netd and the framework will always know how
464xlat is configured, and we'll be able to use that information
in netd.

Test: builds, boots
Test: atest FrameworksNetTests
Change-Id: Ida32d5760c5aecf7aeebef08fdb596291b2ce14a
This commit is contained in:
Lorenzo Colitti
2019-01-08 10:04:25 +09:00
parent 7b0732fff7
commit f7e1739d9b
4 changed files with 164 additions and 29 deletions

View File

@@ -1798,6 +1798,12 @@ public class ConnectivityServiceTest {
fn.test((NetworkCapabilities) cbi.arg));
}
void expectLinkPropertiesLike(Predicate<LinkProperties> fn, MockNetworkAgent agent) {
CallbackInfo cbi = expectCallback(CallbackState.LINK_PROPERTIES, agent);
assertTrue("Received LinkProperties don't match expectations : " + cbi.arg,
fn.test((LinkProperties) cbi.arg));
}
void expectBlockedStatusCallback(boolean expectBlocked, MockNetworkAgent agent) {
CallbackInfo cbi = expectCallback(CallbackState.BLOCKED_STATUS, agent);
boolean actualBlocked = (boolean) cbi.arg;
@@ -5087,6 +5093,9 @@ public class ConnectivityServiceTest {
public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
final String kNat64PrefixString = "2001:db8:64:64:64:64::";
final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
@@ -5110,10 +5119,19 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME);
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
// Clat iface up, expect stack link updated.
// When NAT64 prefix detection succeeds, LinkProperties are updated and clatd is started.
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
mService.mNetdEventCallback.onNat64PrefixEvent(mCellNetworkAgent.getNetwork().netId,
true /* added */, kNat64PrefixString, 96);
LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
assertEquals(0, lpBeforeClat.getStackedLinks().size());
assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
@@ -5130,20 +5148,50 @@ public class ConnectivityServiceTest {
assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
// Add ipv4 address, expect stacked linkproperties be cleaned up
// Add ipv4 address, expect that clatd is stopped and stacked linkproperties are cleaned up.
cellLp.addLinkAddress(myIpv4);
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
// Clat iface removed, expect linkproperties revert to original one
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
assertEquals(cellLp, actualLpAfterIpv4);
// Clean up
// As soon as stop is called, the linkproperties lose the stacked interface.
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
LinkProperties expected = new LinkProperties(cellLp);
expected.setNat64Prefix(kNat64Prefix);
assertEquals(expected, actualLpAfterIpv4);
assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
// The interface removed callback happens but has no effect after stop is called.
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
networkCallback.assertNoCallback();
reset(mMockNetd);
// Remove IPv4 address and expect clatd to be started again.
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 1,
mCellNetworkAgent);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(mCellNetworkAgent.getNetwork().netId,
false /* added */, kNat64PrefixString, 96);
networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
mCellNetworkAgent);
// Clean up.
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
networkCallback.assertNoCallback();

View File

@@ -16,6 +16,7 @@
package com.android.server.connectivity;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.eq;
@@ -28,6 +29,7 @@ import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -55,6 +57,7 @@ public class Nat464XlatTest {
static final String BASE_IFACE = "test0";
static final String STACKED_IFACE = "v4-test0";
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
static final String NAT64_PREFIX = "64:ff9b::/96";
@Mock ConnectivityService mConnectivity;
@Mock NetworkMisc mMisc;
@@ -89,6 +92,15 @@ public class Nat464XlatTest {
when(mConfig.getLinkAddress()).thenReturn(ADDR);
}
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
String msg = String.format("requiresClat expected %b for type=%d state=%s skip464xlat=%b "
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
nai.networkInfo.getDetailedState(),
mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
nai.linkProperties.getLinkAddresses());
assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
}
@Test
public void testRequiresClat() throws Exception {
final int[] supportedTypes = {
@@ -104,20 +116,31 @@ public class Nat464XlatTest {
NetworkInfo.DetailedState.SUSPENDED,
};
LinkProperties oldLp = new LinkProperties(mNai.linkProperties);
for (int type : supportedTypes) {
mNai.networkInfo.setType(type);
for (NetworkInfo.DetailedState state : supportedDetailedStates) {
mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
String msg = String.format("requiresClat expected for type=%d state=%s",
type, state);
mNai.linkProperties.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
assertRequiresClat(false, mNai);
mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
assertRequiresClat(false, mNai);
mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
assertRequiresClat(true, mNai);
mMisc.skip464xlat = true;
String errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
assertFalse(errorMsg, Nat464Xlat.requiresClat(mNai));
assertRequiresClat(false, mNai);
mMisc.skip464xlat = false;
errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
assertTrue(errorMsg, Nat464Xlat.requiresClat(mNai));
assertRequiresClat(true, mNai);
mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
assertRequiresClat(false, mNai);
mNai.linkProperties = new LinkProperties(oldLp);
}
}
}
@@ -127,11 +150,13 @@ public class Nat464XlatTest {
Nat464Xlat nat = makeNat464Xlat();
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
// ConnectivityService starts clat.
nat.start();
verify(mNms).registerObserver(eq(nat));
verify(mNetd).clatdStart(eq(BASE_IFACE));
verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -165,10 +190,12 @@ public class Nat464XlatTest {
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mConnectivity);
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
// ConnectivityService starts clat.
nat.start();
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE));
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -205,7 +232,7 @@ public class Nat464XlatTest {
// ConnectivityService starts clatd again.
nat.start();
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE));
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
if (!interfaceRemovedFirst) {
// Stacked interface removed notification arrives and is ignored.
@@ -252,11 +279,13 @@ public class Nat464XlatTest {
Nat464Xlat nat = makeNat464Xlat();
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
// ConnectivityService starts clat.
nat.start();
verify(mNms).registerObserver(eq(nat));
verify(mNetd).clatdStart(eq(BASE_IFACE));
verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -289,11 +318,13 @@ public class Nat464XlatTest {
public void testStopBeforeClatdStarts() throws Exception {
Nat464Xlat nat = makeNat464Xlat();
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
// ConnectivityService starts clat.
nat.start();
verify(mNms).registerObserver(eq(nat));
verify(mNetd).clatdStart(eq(BASE_IFACE));
verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();
@@ -320,11 +351,13 @@ public class Nat464XlatTest {
public void testStopAndClatdNeverStarts() throws Exception {
Nat464Xlat nat = makeNat464Xlat();
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
// ConnectivityService starts clat.
nat.start();
verify(mNms).registerObserver(eq(nat));
verify(mNetd).clatdStart(eq(BASE_IFACE));
verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();