Manage NAT64 prefix discovery lifecycle in the framework.
Currently NAT64 prefix discovery, which runs in netd, is started by netd itself when a network is programmed with all-IPv6 DNS servers. Unfortunately this is not correct because in many cases we program DNS servers before the network is connected and it's actually possible to send packets to them. In general netd does not have enough visibility into network lifecycle management to decide when to start and stop prefix discovery. So move it into the framework with the rest of the 464xlat control plane. Bug: 65674744 Test: atest FrameworksNetTests Change-Id: I8fa051a9c216d9c05082bf7d0bbb0cbd56000162
This commit is contained in:
@@ -2908,7 +2908,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
e.rethrowFromSystemServer();
|
e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
mNetworkAgentInfos.remove(nai.messenger);
|
mNetworkAgentInfos.remove(nai.messenger);
|
||||||
nai.updateClat();
|
nai.clatd.update();
|
||||||
synchronized (mNetworkForNetId) {
|
synchronized (mNetworkForNetId) {
|
||||||
// Remove the NetworkAgent, but don't mark the netId as
|
// Remove the NetworkAgent, but don't mark the netId as
|
||||||
// available until we've told netd to delete it below.
|
// available until we've told netd to delete it below.
|
||||||
@@ -5249,8 +5249,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
synchronized (networkAgent) {
|
synchronized (networkAgent) {
|
||||||
networkAgent.linkProperties = newLp;
|
networkAgent.linkProperties = newLp;
|
||||||
}
|
}
|
||||||
// Start or stop clat accordingly to network state.
|
// Start or stop DNS64 detection and 464xlat according to network state.
|
||||||
networkAgent.updateClat();
|
networkAgent.clatd.update();
|
||||||
notifyIfacesChangedForNetworkStats();
|
notifyIfacesChangedForNetworkStats();
|
||||||
if (networkAgent.everConnected) {
|
if (networkAgent.everConnected) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ import android.net.NetworkInfo;
|
|||||||
import android.net.RouteInfo;
|
import android.net.RouteInfo;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceSpecificException;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.server.net.BaseNetworkObserver;
|
import com.android.server.net.BaseNetworkObserver;
|
||||||
|
|
||||||
@@ -70,9 +72,10 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
private final NetworkAgentInfo mNetwork;
|
private final NetworkAgentInfo mNetwork;
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
IDLE, // start() not called. Base iface and stacked iface names are null.
|
IDLE, // start() not called. Base iface and stacked iface names are null.
|
||||||
STARTING, // start() called. Base iface and stacked iface names are known.
|
DISCOVERING, // same as IDLE, except prefix discovery in progress.
|
||||||
RUNNING, // start() called, and the stacked iface is known to be up.
|
STARTING, // start() called. Base iface and stacked iface names are known.
|
||||||
|
RUNNING, // start() called, and the stacked iface is known to be up.
|
||||||
}
|
}
|
||||||
|
|
||||||
private IpPrefix mNat64Prefix;
|
private IpPrefix mNat64Prefix;
|
||||||
@@ -88,25 +91,51 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether a network requires clat.
|
* Whether to attempt 464xlat on this network. This is true for an IPv6-only network that is
|
||||||
|
* currently connected and where the NetworkAgent has not disabled 464xlat. It is the signal to
|
||||||
|
* enable NAT64 prefix discovery.
|
||||||
|
*
|
||||||
* @param network the NetworkAgentInfo corresponding to the network.
|
* @param network the NetworkAgentInfo corresponding to the network.
|
||||||
* @return true if the network requires clat, false otherwise.
|
* @return true if the network requires clat, false otherwise.
|
||||||
*/
|
*/
|
||||||
public static boolean requiresClat(NetworkAgentInfo nai) {
|
@VisibleForTesting
|
||||||
|
protected static boolean requiresClat(NetworkAgentInfo nai) {
|
||||||
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
|
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
|
||||||
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
|
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
|
||||||
final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
|
final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
|
||||||
|
|
||||||
// We only run clat on networks that have a global IPv6 address and a NAT64 prefix and don't
|
// Only run clat on networks that have a global IPv6 address and don't have a native IPv4
|
||||||
// have a native IPv4 address.
|
// address.
|
||||||
LinkProperties lp = nai.linkProperties;
|
LinkProperties lp = nai.linkProperties;
|
||||||
final boolean isNat64Network = (lp != null) && lp.hasGlobalIPv6Address()
|
final boolean isIpv6OnlyNetwork = (lp != null) && lp.hasGlobalIPv6Address()
|
||||||
&& lp.getNat64Prefix() != null && !lp.hasIPv4Address();
|
&& !lp.hasIPv4Address();
|
||||||
|
|
||||||
// If the network tells us it doesn't use clat, respect that.
|
// If the network tells us it doesn't use clat, respect that.
|
||||||
final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat;
|
final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat;
|
||||||
|
|
||||||
return supported && connected && isNat64Network && !skip464xlat;
|
return supported && connected && isIpv6OnlyNetwork && !skip464xlat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the clat demon should be started on this network now. This is true if requiresClat is
|
||||||
|
* true and a NAT64 prefix has been discovered.
|
||||||
|
*
|
||||||
|
* @param nai the NetworkAgentInfo corresponding to the network.
|
||||||
|
* @return true if the network should start clat, false otherwise.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
protected static boolean shouldStartClat(NetworkAgentInfo nai) {
|
||||||
|
LinkProperties lp = nai.linkProperties;
|
||||||
|
return requiresClat(nai) && lp != null && lp.getNat64Prefix() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if we have started prefix discovery and not yet stopped it (regardless of
|
||||||
|
* whether it is still running or has succeeded).
|
||||||
|
* A true result corresponds to internal states DISCOVERING, STARTING and RUNNING.
|
||||||
|
*/
|
||||||
|
public boolean isPrefixDiscoveryStarted() {
|
||||||
|
return mState == State.DISCOVERING || isStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,7 +143,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
* A true result corresponds to internal states STARTING and RUNNING.
|
* A true result corresponds to internal states STARTING and RUNNING.
|
||||||
*/
|
*/
|
||||||
public boolean isStarted() {
|
public boolean isStarted() {
|
||||||
return mState != State.IDLE;
|
return (mState == State.STARTING || mState == State.RUNNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,7 +199,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
/**
|
/**
|
||||||
* Unregister as a base observer for the stacked interface, and clear internal state.
|
* Unregister as a base observer for the stacked interface, and clear internal state.
|
||||||
*/
|
*/
|
||||||
private void enterIdleState() {
|
private void leaveStartedState() {
|
||||||
try {
|
try {
|
||||||
mNMService.unregisterObserver(this);
|
mNMService.unregisterObserver(this);
|
||||||
} catch (RemoteException | IllegalStateException e) {
|
} catch (RemoteException | IllegalStateException e) {
|
||||||
@@ -179,12 +208,16 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
mIface = null;
|
mIface = null;
|
||||||
mBaseIface = null;
|
mBaseIface = null;
|
||||||
mState = State.IDLE;
|
mState = State.IDLE;
|
||||||
|
if (requiresClat(mNetwork)) {
|
||||||
|
mState = State.DISCOVERING;
|
||||||
|
} else {
|
||||||
|
stopPrefixDiscovery();
|
||||||
|
mState = State.IDLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@VisibleForTesting
|
||||||
* Starts the clat daemon.
|
protected void start() {
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
if (isStarted()) {
|
if (isStarted()) {
|
||||||
Slog.e(TAG, "startClat: already started");
|
Slog.e(TAG, "startClat: already started");
|
||||||
return;
|
return;
|
||||||
@@ -205,10 +238,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
enterStartingState(baseIface);
|
enterStartingState(baseIface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@VisibleForTesting
|
||||||
* Stops the clat daemon.
|
protected void stop() {
|
||||||
*/
|
|
||||||
public void stop() {
|
|
||||||
if (!isStarted()) {
|
if (!isStarted()) {
|
||||||
Slog.e(TAG, "stopClat: already stopped");
|
Slog.e(TAG, "stopClat: already stopped");
|
||||||
return;
|
return;
|
||||||
@@ -224,11 +255,10 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
String iface = mIface;
|
String iface = mIface;
|
||||||
boolean wasRunning = isRunning();
|
boolean wasRunning = isRunning();
|
||||||
|
|
||||||
// Enter IDLE state before updating LinkProperties. handleUpdateLinkProperties ends up
|
// Change state before updating LinkProperties. handleUpdateLinkProperties ends up calling
|
||||||
// calling fixupLinkProperties, and if at that time the state is still RUNNING,
|
// fixupLinkProperties, and if at that time the state is still RUNNING, fixupLinkProperties
|
||||||
// fixupLinkProperties would wrongly inform ConnectivityService that there is still a
|
// would wrongly inform ConnectivityService that there is still a stacked interface.
|
||||||
// stacked interface.
|
leaveStartedState();
|
||||||
enterIdleState();
|
|
||||||
|
|
||||||
if (wasRunning) {
|
if (wasRunning) {
|
||||||
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
|
||||||
@@ -237,6 +267,51 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startPrefixDiscovery() {
|
||||||
|
try {
|
||||||
|
mNetd.resolverStartPrefix64Discovery(getNetId());
|
||||||
|
mState = State.DISCOVERING;
|
||||||
|
} catch (RemoteException | ServiceSpecificException e) {
|
||||||
|
Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPrefixDiscovery() {
|
||||||
|
try {
|
||||||
|
mNetd.resolverStopPrefix64Discovery(getNetId());
|
||||||
|
} catch (RemoteException | ServiceSpecificException e) {
|
||||||
|
Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts/stops NAT64 prefix discovery and clatd as necessary.
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
// TODO: turn this class into a proper StateMachine. // http://b/126113090
|
||||||
|
if (requiresClat(mNetwork)) {
|
||||||
|
if (!isPrefixDiscoveryStarted()) {
|
||||||
|
startPrefixDiscovery();
|
||||||
|
} else if (shouldStartClat(mNetwork)) {
|
||||||
|
// NAT64 prefix detected. Start clatd.
|
||||||
|
// TODO: support the NAT64 prefix changing after it's been discovered. There is no
|
||||||
|
// need to support this at the moment because it cannot happen without changes to
|
||||||
|
// the Dns64Configuration code in netd.
|
||||||
|
start();
|
||||||
|
} else {
|
||||||
|
// NAT64 prefix removed. Stop clatd and go back into DISCOVERING state.
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Network no longer requires clat. Stop clat and prefix discovery.
|
||||||
|
if (isStarted()) {
|
||||||
|
stop();
|
||||||
|
} else if (isPrefixDiscoveryStarted()) {
|
||||||
|
leaveStartedState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setNat64Prefix(IpPrefix nat64Prefix) {
|
public void setNat64Prefix(IpPrefix nat64Prefix) {
|
||||||
mNat64Prefix = nat64Prefix;
|
mNat64Prefix = nat64Prefix;
|
||||||
}
|
}
|
||||||
@@ -297,6 +372,20 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
* Adds stacked link on base link and transitions to RUNNING state.
|
* Adds stacked link on base link and transitions to RUNNING state.
|
||||||
*/
|
*/
|
||||||
private void handleInterfaceLinkStateChanged(String iface, boolean up) {
|
private void handleInterfaceLinkStateChanged(String iface, boolean up) {
|
||||||
|
// TODO: if we call start(), then stop(), then start() again, and the
|
||||||
|
// interfaceLinkStateChanged notification for the first start is delayed past the first
|
||||||
|
// stop, then the code becomes out of sync with system state and will behave incorrectly.
|
||||||
|
//
|
||||||
|
// This is not trivial to fix because:
|
||||||
|
// 1. It is not guaranteed that start() will eventually result in the interface coming up,
|
||||||
|
// because there could be an error starting clat (e.g., if the interface goes down before
|
||||||
|
// the packet socket can be bound).
|
||||||
|
// 2. If start is called multiple times, there is nothing in the interfaceLinkStateChanged
|
||||||
|
// notification that says which start() call the interface was created by.
|
||||||
|
//
|
||||||
|
// Once this code is converted to StateMachine, it will be possible to use deferMessage to
|
||||||
|
// ensure it stays in STARTING state until the interfaceLinkStateChanged notification fires,
|
||||||
|
// and possibly use a timeout (or provide some guarantees at the lower layer) to address #1.
|
||||||
if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
|
if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -348,4 +437,9 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "mBaseIface: " + mBaseIface + ", mIface: " + mIface + ", mState: " + mState;
|
return "mBaseIface: " + mBaseIface + ", mIface: " + mIface + ", mState: " + mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected int getNetId() {
|
||||||
|
return mNetwork.network.netId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -592,15 +592,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
|
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts or stops clatd as required. */
|
|
||||||
public void updateClat() {
|
|
||||||
if (!clatd.isStarted() && Nat464Xlat.requiresClat(this)) {
|
|
||||||
clatd.start();
|
|
||||||
} else if (clatd.isStarted() && !Nat464Xlat.requiresClat(this)) {
|
|
||||||
clatd.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "NetworkAgentInfo{ ni{" + networkInfo + "} "
|
return "NetworkAgentInfo{ ni{" + networkInfo + "} "
|
||||||
+ "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} "
|
+ "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} "
|
||||||
|
|||||||
@@ -5103,8 +5103,9 @@ public class ConnectivityServiceTest {
|
|||||||
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
mCm.registerNetworkCallback(networkRequest, networkCallback);
|
mCm.registerNetworkCallback(networkRequest, networkCallback);
|
||||||
|
|
||||||
// Prepare ipv6 only link properties and connect.
|
// Prepare ipv6 only link properties.
|
||||||
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
final int cellNetId = mCellNetworkAgent.getNetwork().netId;
|
||||||
final LinkProperties cellLp = new LinkProperties();
|
final LinkProperties cellLp = new LinkProperties();
|
||||||
cellLp.setInterfaceName(MOBILE_IFNAME);
|
cellLp.setInterfaceName(MOBILE_IFNAME);
|
||||||
cellLp.addLinkAddress(myIpv6);
|
cellLp.addLinkAddress(myIpv6);
|
||||||
@@ -5114,17 +5115,37 @@ public class ConnectivityServiceTest {
|
|||||||
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
|
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
|
||||||
.thenReturn(getClatInterfaceConfig(myIpv4));
|
.thenReturn(getClatInterfaceConfig(myIpv4));
|
||||||
|
|
||||||
// Connect with ipv6 link properties, then expect clat setup ipv4 and update link
|
// Connect with ipv6 link properties. Expect prefix discovery to be started.
|
||||||
// properties properly.
|
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
mCellNetworkAgent.connect(true);
|
mCellNetworkAgent.connect(true);
|
||||||
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
||||||
|
verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
|
||||||
|
|
||||||
// When NAT64 prefix detection succeeds, LinkProperties are updated and clatd is started.
|
// Switching default network updates TCP buffer sizes.
|
||||||
|
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
|
||||||
|
|
||||||
|
// Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
|
||||||
|
// the NAT64 prefix was removed because one was never discovered.
|
||||||
|
cellLp.addLinkAddress(myIpv4);
|
||||||
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
|
verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockNetd);
|
||||||
|
reset(mMockNetd);
|
||||||
|
|
||||||
|
// Remove IPv4 address. Expect prefix discovery to be started again.
|
||||||
|
cellLp.removeLinkAddress(myIpv4);
|
||||||
|
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
|
||||||
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
|
verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
|
||||||
|
|
||||||
|
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
|
||||||
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
|
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
|
||||||
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
|
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
|
||||||
mService.mNetdEventCallback.onNat64PrefixEvent(mCellNetworkAgent.getNetwork().netId,
|
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
|
||||||
true /* added */, kNat64PrefixString, 96);
|
kNat64PrefixString, 96);
|
||||||
LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
|
LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
|
||||||
CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
|
CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
|
||||||
assertEquals(0, lpBeforeClat.getStackedLinks().size());
|
assertEquals(0, lpBeforeClat.getStackedLinks().size());
|
||||||
@@ -5148,15 +5169,17 @@ public class ConnectivityServiceTest {
|
|||||||
assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
|
assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
|
||||||
assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
|
assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
|
||||||
|
|
||||||
// Add ipv4 address, expect that clatd is stopped and stacked linkproperties are cleaned up.
|
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
|
||||||
|
// linkproperties are cleaned up.
|
||||||
cellLp.addLinkAddress(myIpv4);
|
cellLp.addLinkAddress(myIpv4);
|
||||||
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
|
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
|
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
|
||||||
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
|
||||||
|
|
||||||
// As soon as stop is called, the linkproperties lose the stacked interface.
|
// As soon as stop is called, the linkproperties lose the stacked interface.
|
||||||
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
|
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
|
||||||
LinkProperties expected = new LinkProperties(cellLp);
|
LinkProperties expected = new LinkProperties(cellLp);
|
||||||
expected.setNat64Prefix(kNat64Prefix);
|
expected.setNat64Prefix(kNat64Prefix);
|
||||||
@@ -5167,25 +5190,39 @@ public class ConnectivityServiceTest {
|
|||||||
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
|
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
|
||||||
networkCallback.assertNoCallback();
|
networkCallback.assertNoCallback();
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockNetd);
|
||||||
reset(mMockNetd);
|
reset(mMockNetd);
|
||||||
|
|
||||||
// Remove IPv4 address and expect clatd to be started again.
|
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
|
||||||
|
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
|
||||||
|
kNat64PrefixString, 96);
|
||||||
|
networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
|
||||||
|
mCellNetworkAgent);
|
||||||
|
|
||||||
|
// Remove IPv4 address and expect prefix discovery and clatd to be started again.
|
||||||
cellLp.removeLinkAddress(myIpv4);
|
cellLp.removeLinkAddress(myIpv4);
|
||||||
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
|
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
|
||||||
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
|
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
|
verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
|
||||||
|
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
|
||||||
|
kNat64PrefixString, 96);
|
||||||
|
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
|
||||||
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
|
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
|
||||||
|
|
||||||
|
|
||||||
// Clat iface comes up. Expect stacked link to be added.
|
// Clat iface comes up. Expect stacked link to be added.
|
||||||
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
|
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
|
||||||
networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 1,
|
networkCallback.expectLinkPropertiesLike(
|
||||||
|
(lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null,
|
||||||
mCellNetworkAgent);
|
mCellNetworkAgent);
|
||||||
|
|
||||||
// NAT64 prefix is removed. Expect that clat is stopped.
|
// NAT64 prefix is removed. Expect that clat is stopped.
|
||||||
mService.mNetdEventCallback.onNat64PrefixEvent(mCellNetworkAgent.getNetwork().netId,
|
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
|
||||||
false /* added */, kNat64PrefixString, 96);
|
kNat64PrefixString, 96);
|
||||||
networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
|
networkCallback.expectLinkPropertiesLike(
|
||||||
|
(lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null,
|
||||||
mCellNetworkAgent);
|
mCellNetworkAgent);
|
||||||
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
|
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
|
||||||
networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
|
networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class Nat464XlatTest {
|
|||||||
static final String STACKED_IFACE = "v4-test0";
|
static final String STACKED_IFACE = "v4-test0";
|
||||||
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
|
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
|
||||||
static final String NAT64_PREFIX = "64:ff9b::/96";
|
static final String NAT64_PREFIX = "64:ff9b::/96";
|
||||||
|
static final int NETID = 42;
|
||||||
|
|
||||||
@Mock ConnectivityService mConnectivity;
|
@Mock ConnectivityService mConnectivity;
|
||||||
@Mock NetworkMisc mMisc;
|
@Mock NetworkMisc mMisc;
|
||||||
@@ -70,7 +71,11 @@ public class Nat464XlatTest {
|
|||||||
Handler mHandler;
|
Handler mHandler;
|
||||||
|
|
||||||
Nat464Xlat makeNat464Xlat() {
|
Nat464Xlat makeNat464Xlat() {
|
||||||
return new Nat464Xlat(mNai, mNetd, mNms);
|
return new Nat464Xlat(mNai, mNetd, mNms) {
|
||||||
|
@Override protected int getNetId() {
|
||||||
|
return NETID;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -93,7 +98,7 @@ public class Nat464XlatTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
|
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
|
||||||
String msg = String.format("requiresClat expected %b for type=%d state=%s skip464xlat=%b "
|
String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
|
||||||
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
|
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
|
||||||
nai.networkInfo.getDetailedState(),
|
nai.networkInfo.getDetailedState(),
|
||||||
mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
|
mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
|
||||||
@@ -101,6 +106,15 @@ public class Nat464XlatTest {
|
|||||||
assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
|
assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) {
|
||||||
|
String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
|
||||||
|
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
|
||||||
|
nai.networkInfo.getDetailedState(),
|
||||||
|
mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
|
||||||
|
nai.linkProperties.getLinkAddresses());
|
||||||
|
assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequiresClat() throws Exception {
|
public void testRequiresClat() throws Exception {
|
||||||
final int[] supportedTypes = {
|
final int[] supportedTypes = {
|
||||||
@@ -124,21 +138,35 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
mNai.linkProperties.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
|
mNai.linkProperties.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
|
||||||
assertRequiresClat(false, mNai);
|
assertRequiresClat(false, mNai);
|
||||||
|
assertShouldStartClat(false, mNai);
|
||||||
|
|
||||||
mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
|
mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
|
||||||
assertRequiresClat(false, mNai);
|
assertRequiresClat(false, mNai);
|
||||||
|
assertShouldStartClat(false, mNai);
|
||||||
|
|
||||||
mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
|
mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
|
||||||
assertRequiresClat(true, mNai);
|
assertRequiresClat(true, mNai);
|
||||||
|
assertShouldStartClat(true, mNai);
|
||||||
|
|
||||||
mMisc.skip464xlat = true;
|
mMisc.skip464xlat = true;
|
||||||
assertRequiresClat(false, mNai);
|
assertRequiresClat(false, mNai);
|
||||||
|
assertShouldStartClat(false, mNai);
|
||||||
|
|
||||||
mMisc.skip464xlat = false;
|
mMisc.skip464xlat = false;
|
||||||
assertRequiresClat(true, mNai);
|
assertRequiresClat(true, mNai);
|
||||||
|
assertShouldStartClat(true, mNai);
|
||||||
|
|
||||||
mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
|
mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
|
||||||
assertRequiresClat(false, mNai);
|
assertRequiresClat(false, mNai);
|
||||||
|
assertShouldStartClat(false, mNai);
|
||||||
|
|
||||||
|
mNai.linkProperties.removeLinkAddress(new LinkAddress("192.0.2.2/24"));
|
||||||
|
assertRequiresClat(true, mNai);
|
||||||
|
assertShouldStartClat(true, mNai);
|
||||||
|
|
||||||
|
mNai.linkProperties.setNat64Prefix(null);
|
||||||
|
assertRequiresClat(true, mNai);
|
||||||
|
assertShouldStartClat(false, mNai);
|
||||||
|
|
||||||
mNai.linkProperties = new LinkProperties(oldLp);
|
mNai.linkProperties = new LinkProperties(oldLp);
|
||||||
}
|
}
|
||||||
@@ -152,7 +180,7 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
||||||
|
|
||||||
// ConnectivityService starts clat.
|
// Start clat.
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
verify(mNms).registerObserver(eq(nat));
|
verify(mNms).registerObserver(eq(nat));
|
||||||
@@ -168,7 +196,7 @@ public class Nat464XlatTest {
|
|||||||
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
assertRunning(nat);
|
assertRunning(nat);
|
||||||
|
|
||||||
// ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
|
// Stop clat (Network disconnects, IPv4 addr appears, ...).
|
||||||
nat.stop();
|
nat.stop();
|
||||||
|
|
||||||
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
||||||
@@ -176,6 +204,7 @@ public class Nat464XlatTest {
|
|||||||
verify(mNms).unregisterObserver(eq(nat));
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
||||||
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
|
verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
|
||||||
assertIdle(nat);
|
assertIdle(nat);
|
||||||
|
|
||||||
// Stacked interface removed notification arrives and is ignored.
|
// Stacked interface removed notification arrives and is ignored.
|
||||||
@@ -192,7 +221,6 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
||||||
|
|
||||||
// ConnectivityService starts clat.
|
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
|
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
|
||||||
@@ -229,7 +257,6 @@ public class Nat464XlatTest {
|
|||||||
assertIdle(nat);
|
assertIdle(nat);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
// ConnectivityService starts clatd again.
|
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
|
inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
|
||||||
@@ -281,7 +308,6 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
||||||
|
|
||||||
// ConnectivityService starts clat.
|
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
verify(mNms).registerObserver(eq(nat));
|
verify(mNms).registerObserver(eq(nat));
|
||||||
@@ -304,6 +330,7 @@ public class Nat464XlatTest {
|
|||||||
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
||||||
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
|
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
|
||||||
verify(mNms).unregisterObserver(eq(nat));
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
|
||||||
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
assertTrue(c.getValue().getStackedLinks().isEmpty());
|
||||||
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
|
||||||
assertIdle(nat);
|
assertIdle(nat);
|
||||||
@@ -320,7 +347,6 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
||||||
|
|
||||||
// ConnectivityService starts clat.
|
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
verify(mNms).registerObserver(eq(nat));
|
verify(mNms).registerObserver(eq(nat));
|
||||||
@@ -331,13 +357,13 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
||||||
verify(mNms).unregisterObserver(eq(nat));
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
|
||||||
assertIdle(nat);
|
assertIdle(nat);
|
||||||
|
|
||||||
// In-flight interface up notification arrives: no-op
|
// In-flight interface up notification arrives: no-op
|
||||||
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
|
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
|
||||||
mLooper.dispatchNext();
|
mLooper.dispatchNext();
|
||||||
|
|
||||||
|
|
||||||
// Interface removed notification arrives after stopClatd() takes effect: no-op.
|
// Interface removed notification arrives after stopClatd() takes effect: no-op.
|
||||||
nat.interfaceRemoved(STACKED_IFACE);
|
nat.interfaceRemoved(STACKED_IFACE);
|
||||||
mLooper.dispatchNext();
|
mLooper.dispatchNext();
|
||||||
@@ -353,7 +379,6 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
|
||||||
|
|
||||||
// ConnectivityService starts clat.
|
|
||||||
nat.start();
|
nat.start();
|
||||||
|
|
||||||
verify(mNms).registerObserver(eq(nat));
|
verify(mNms).registerObserver(eq(nat));
|
||||||
@@ -364,6 +389,7 @@ public class Nat464XlatTest {
|
|||||||
|
|
||||||
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
verify(mNetd).clatdStop(eq(BASE_IFACE));
|
||||||
verify(mNms).unregisterObserver(eq(nat));
|
verify(mNms).unregisterObserver(eq(nat));
|
||||||
|
verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
|
||||||
assertIdle(nat);
|
assertIdle(nat);
|
||||||
|
|
||||||
verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
|
verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
|
||||||
|
|||||||
Reference in New Issue
Block a user