Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9b77312 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by android-build-merger
Browse files

Merge changes from topic "nat64"

am: a02847ec

Change-Id: I3f7f74c197dd5da3db7d8d41fa4a26aacf38c2e8
parents 817f75df a02847ec
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
import android.net.MatchAllNetworkSpecifier;
@@ -1740,6 +1742,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
                }
            }
        }

        @Override
        public void onNat64PrefixEvent(int netId, boolean added,
                                       String prefixString, int prefixLength) {
            mHandler.post(() -> handleNat64PrefixEvent(netId, added, prefixString, prefixLength));
        }
    };

    @VisibleForTesting
@@ -2767,6 +2775,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
        handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
    }

    private void handleNat64PrefixEvent(int netId, boolean added, String prefixString,
            int prefixLength) {
        NetworkAgentInfo nai = mNetworkForNetId.get(netId);
        if (nai == null) return;

        log(String.format("NAT64 prefix %s on netId %d: %s/%d",
                          (added ? "added" : "removed"), netId, prefixString, prefixLength));

        IpPrefix prefix = null;
        if (added) {
            try {
                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixString),
                        prefixLength);
            } catch (IllegalArgumentException e) {
                loge("Invalid NAT64 prefix " + prefixString + "/" + prefixLength);
                return;
            }
        }

        nai.clatd.setNat64Prefix(prefix);
        handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
    }

    private void updateLingerState(NetworkAgentInfo nai, long now) {
        // 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
        // 2. If the network was lingering and there are now requests, unlinger it.
@@ -2882,7 +2913,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
            e.rethrowFromSystemServer();
        }
        mNetworkAgentInfos.remove(nai.messenger);
        nai.maybeStopClat();
        nai.clatd.update();
        synchronized (mNetworkForNetId) {
            // Remove the NetworkAgent, but don't mark the netId as
            // available until we've told netd to delete it below.
@@ -5190,11 +5221,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
            LinkProperties oldLp) {
        int netId = networkAgent.network.netId;

        // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
        // we do anything else, make sure its LinkProperties are accurate.
        if (networkAgent.clatd != null) {
        // The NetworkAgentInfo does not know whether clatd is running on its network or not, or
        // whether there is a NAT64 prefix. Before we do anything else, make sure its LinkProperties
        // are accurate.
        networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
        }

        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
        updateMtu(newLp, oldLp);
@@ -5224,8 +5254,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
            synchronized (networkAgent) {
                networkAgent.linkProperties = newLp;
            }
            // Start or stop clat accordingly to network state.
            networkAgent.updateClat(mNMS);
            // Start or stop DNS64 detection and 464xlat according to network state.
            networkAgent.clatd.update();
            notifyIfacesChangedForNetworkStats();
            if (networkAgent.everConnected) {
                try {
+172 −67
Original line number Diff line number Diff line
@@ -18,19 +18,24 @@ package com.android.server.connectivity;

import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InetAddresses;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.RouteInfo;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.net.BaseNetworkObserver;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.Objects;

/**
@@ -68,14 +73,15 @@ public class Nat464Xlat extends BaseNetworkObserver {

    private enum State {
        IDLE,         // start() not called. Base iface and stacked iface names are null.
        DISCOVERING,  // same as IDLE, except prefix discovery in progress.
        STARTING,     // start() called. Base iface and stacked iface names are known.
        RUNNING,      // start() called, and the stacked iface is known to be up.
        STOPPING;   // stop() called, this Nat464Xlat is still registered as a network observer for
                    // the stacked interface.
    }

    private IpPrefix mNat64Prefix;
    private String mBaseIface;
    private String mIface;
    private Inet6Address mIPv6Address;
    private State mState = State.IDLE;

    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
@@ -85,20 +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.
     * @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_*.
        final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
        final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
        // We only run clat on networks that don't have a native IPv4 address.
        final boolean hasIPv4Address =
                (nai.linkProperties != null) && nai.linkProperties.hasIPv4Address();
        final boolean skip464xlat =
                (nai.netMisc() != null) && nai.netMisc().skip464xlat;
        return supported && connected && !hasIPv4Address && !skip464xlat;

        // Only run clat on networks that have a global IPv6 address and don't have a native IPv4
        // address.
        LinkProperties lp = nai.linkProperties;
        final boolean isIpv6OnlyNetwork = (lp != null) && lp.hasGlobalIPv6Address()
                && !lp.hasIPv4Address();

        // If the network tells us it doesn't use clat, respect that.
        final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().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();
    }

    /**
@@ -106,7 +143,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
     * A true result corresponds to internal states STARTING and RUNNING.
     */
    public boolean isStarted() {
        return mState != State.IDLE;
        return (mState == State.STARTING || mState == State.RUNNING);
    }

    /**
@@ -123,13 +160,6 @@ public class Nat464Xlat extends BaseNetworkObserver {
        return mState == State.RUNNING;
    }

    /**
     * @return true if clatd has been stopped.
     */
    public boolean isStopping() {
        return mState == State.STOPPING;
    }

    /**
     * Start clatd, register this Nat464Xlat as a network observer for the stacked interface,
     * and set internal state.
@@ -138,18 +168,24 @@ public class Nat464Xlat extends BaseNetworkObserver {
        try {
            mNMService.registerObserver(this);
        } catch (RemoteException e) {
            Slog.e(TAG,
                    "startClat: Can't register interface observer for clat on " + mNetwork.name());
            Slog.e(TAG, "Can't register interface observer for clat on " + mNetwork.name());
            return;
        }

        String addrStr = null;
        try {
            mNetd.clatdStart(baseIface);
        } catch(RemoteException|IllegalStateException e) {
            Slog.e(TAG, "Error starting clatd on " + baseIface, e);
            addrStr = mNetd.clatdStart(baseIface, mNat64Prefix.toString());
        } catch (RemoteException | ServiceSpecificException e) {
            Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
        }
        mIface = CLAT_PREFIX + baseIface;
        mBaseIface = baseIface;
        mState = State.STARTING;
        try {
            mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
        } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
            Slog.e(TAG, "Invalid IPv6 address " + addrStr);
        }
    }

    /**
@@ -160,38 +196,28 @@ public class Nat464Xlat extends BaseNetworkObserver {
        mState = State.RUNNING;
    }

    /**
     * Stop clatd, and turn ND offload on if it had been turned off.
     */
    private void enterStoppingState() {
        try {
            mNetd.clatdStop(mBaseIface);
        } catch(RemoteException|IllegalStateException e) {
            Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
        }

        mState = State.STOPPING;
    }

    /**
     * Unregister as a base observer for the stacked interface, and clear internal state.
     */
    private void enterIdleState() {
    private void leaveStartedState() {
        try {
            mNMService.unregisterObserver(this);
        } catch (RemoteException | IllegalStateException e) {
            Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface, e);
            Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
        }

        mIface = null;
        mBaseIface = null;
        mState = State.IDLE;
        if (requiresClat(mNetwork)) {
            mState = State.DISCOVERING;
        } else {
            stopPrefixDiscovery();
            mState = State.IDLE;
        }
    }

    /**
     * Starts the clat daemon.
     */
    public void start() {
    @VisibleForTesting
    protected void start() {
        if (isStarted()) {
            Slog.e(TAG, "startClat: already started");
            return;
@@ -212,28 +238,92 @@ public class Nat464Xlat extends BaseNetworkObserver {
        enterStartingState(baseIface);
    }

    /**
     * Stops the clat daemon.
     */
    public void stop() {
    @VisibleForTesting
    protected void stop() {
        if (!isStarted()) {
            Slog.e(TAG, "stopClat: already stopped");
            return;
        }

        Slog.i(TAG, "Stopping clatd on " + mBaseIface);
        try {
            mNetd.clatdStop(mBaseIface);
        } catch (RemoteException | ServiceSpecificException e) {
            Slog.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
        }

        String iface = mIface;
        boolean wasRunning = isRunning();

        // Change state before updating LinkProperties. handleUpdateLinkProperties ends up calling
        // fixupLinkProperties, and if at that time the state is still RUNNING, fixupLinkProperties
        // would wrongly inform ConnectivityService that there is still a stacked interface.
        leaveStartedState();

        if (wasRunning) {
            LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
            lp.removeStackedLink(iface);
            mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
        }
    }

        boolean wasStarting = isStarting();
        enterStoppingState();
        if (wasStarting) {
            enterIdleState();
    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) {
        mNat64Prefix = nat64Prefix;
    }

    /**
     * Copies the stacked clat link in oldLp, if any, to the passed LinkProperties.
     * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
     * has no idea that 464xlat is running on top of it.
     */
    public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) {
        lp.setNat64Prefix(mNat64Prefix);

        if (!isRunning()) {
            return;
        }
@@ -282,6 +372,20 @@ public class Nat464Xlat extends BaseNetworkObserver {
     * Adds stacked link on base link and transitions to RUNNING state.
     */
    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)) {
            return;
        }
@@ -307,20 +411,16 @@ public class Nat464Xlat extends BaseNetworkObserver {
        if (!Objects.equals(mIface, iface)) {
            return;
        }
        if (!isRunning() && !isStopping()) {
        if (!isRunning()) {
            return;
        }

        Slog.i(TAG, "interface " + iface + " removed");
        if (!isStopping()) {
            // Ensure clatd is stopped if stop() has not been called: this likely means that clatd
            // has crashed.
            enterStoppingState();
        }
        enterIdleState();
        LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
        lp.removeStackedLink(iface);
        mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
        // If we're running, and the interface was removed, then we didn't call stop(), and it's
        // likely that clatd crashed. Ensure we call stop() so we can start clatd again. Calling
        // stop() will also update LinkProperties, and if clatd crashed, the LinkProperties update
        // will cause ConnectivityService to call start() again.
        stop();
    }

    @Override
@@ -337,4 +437,9 @@ public class Nat464Xlat extends BaseNetworkObserver {
    public String toString() {
        return "mBaseIface: " + mBaseIface + ", mIface: " + mIface + ", mState: " + mState;
    }

    @VisibleForTesting
    protected int getNetId() {
        return mNetwork.network.netId;
    }
}
+2 −31
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    public final AsyncChannel asyncChannel;

    // Used by ConnectivityService to keep track of 464xlat.
    public Nat464Xlat clatd;
    public final Nat464Xlat clatd;

    // Set after asynchronous creation of the NetworkMonitor.
    private volatile INetworkMonitor mNetworkMonitor;
@@ -244,8 +244,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
    private static final String TAG = ConnectivityService.class.getSimpleName();
    private static final boolean VDBG = false;
    private final ConnectivityService mConnService;
    private final INetd mNetd;
    private final INetworkManagementService mNMS;
    private final Context mContext;
    private final Handler mHandler;

@@ -260,9 +258,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        linkProperties = lp;
        networkCapabilities = nc;
        currentScore = score;
        clatd = new Nat464Xlat(this, netd, nms);
        mConnService = connService;
        mNetd = netd;
        mNMS = nms;
        mContext = context;
        mHandler = handler;
        networkMisc = misc;
@@ -595,32 +592,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
        for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
    }

    public void updateClat(INetworkManagementService netd) {
        if (Nat464Xlat.requiresClat(this)) {
            maybeStartClat();
        } else {
            maybeStopClat();
        }
    }

    /** Ensure clat has started for this network. */
    public void maybeStartClat() {
        if (clatd != null && clatd.isStarted()) {
            return;
        }
        clatd = new Nat464Xlat(this, mNetd, mNMS);
        clatd.start();
    }

    /** Ensure clat has stopped for this network. */
    public void maybeStopClat() {
        if (clatd == null) {
            return;
        }
        clatd.stop();
        clatd = null;
    }

    public String toString() {
        return "NetworkAgentInfo{ ni{" + networkInfo + "}  "
                + "network{" + network + "}  nethandle{" + network.getNetworkHandle() + "}  "
+109 −20

File changed.

Preview size limit exceeded, changes collapsed.

+171 −24

File changed.

Preview size limit exceeded, changes collapsed.