Merge "Pass upstream prefixes to bpf tethering offload" into main
This commit is contained in:
@@ -66,6 +66,7 @@ import android.util.SparseArray;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.MessageUtils;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
@@ -92,6 +93,7 @@ import java.net.Inet6Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -298,6 +300,8 @@ public class IpServer extends StateMachineShim {
|
||||
|
||||
private int mLastIPv6UpstreamIfindex = 0;
|
||||
private boolean mUpstreamSupportsBpf = false;
|
||||
@NonNull
|
||||
private Set<IpPrefix> mLastIPv6UpstreamPrefixes = Collections.emptySet();
|
||||
|
||||
private class MyNeighborEventConsumer implements IpNeighborMonitor.NeighborEventConsumer {
|
||||
public void accept(NeighborEvent e) {
|
||||
@@ -782,13 +786,8 @@ public class IpServer extends StateMachineShim {
|
||||
|
||||
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
|
||||
|
||||
for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
|
||||
if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
|
||||
|
||||
final IpPrefix prefix = new IpPrefix(
|
||||
linkAddr.getAddress(), linkAddr.getPrefixLength());
|
||||
params.prefixes.add(prefix);
|
||||
|
||||
params.prefixes = getTetherableIpv6Prefixes(v6only);
|
||||
for (IpPrefix prefix : params.prefixes) {
|
||||
final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
|
||||
if (dnsServer != null) {
|
||||
params.dnses.add(dnsServer);
|
||||
@@ -808,9 +807,12 @@ public class IpServer extends StateMachineShim {
|
||||
|
||||
// Not support BPF on virtual upstream interface
|
||||
final boolean upstreamSupportsBpf = upstreamIface != null && !isVcnInterface(upstreamIface);
|
||||
updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, upstreamSupportsBpf);
|
||||
final Set<IpPrefix> upstreamPrefixes = params != null ? params.prefixes : Set.of();
|
||||
updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, mLastIPv6UpstreamPrefixes,
|
||||
upstreamIfIndex, upstreamPrefixes, upstreamSupportsBpf);
|
||||
mLastIPv6LinkProperties = v6only;
|
||||
mLastIPv6UpstreamIfindex = upstreamIfIndex;
|
||||
mLastIPv6UpstreamPrefixes = upstreamPrefixes;
|
||||
mUpstreamSupportsBpf = upstreamSupportsBpf;
|
||||
if (mDadProxy != null) {
|
||||
mDadProxy.setUpstreamIface(upstreamIfaceParams);
|
||||
@@ -959,14 +961,17 @@ public class IpServer extends StateMachineShim {
|
||||
return supportsBpf ? ifindex : NO_UPSTREAM;
|
||||
}
|
||||
|
||||
// Handles updates to IPv6 forwarding rules if the upstream changes.
|
||||
private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
|
||||
boolean upstreamSupportsBpf) {
|
||||
// Handles updates to IPv6 forwarding rules if the upstream or its prefixes change.
|
||||
private void updateIpv6ForwardingRules(int prevUpstreamIfindex,
|
||||
@NonNull Set<IpPrefix> prevUpstreamPrefixes, int upstreamIfindex,
|
||||
@NonNull Set<IpPrefix> upstreamPrefixes, boolean upstreamSupportsBpf) {
|
||||
// If the upstream interface has changed, remove all rules and re-add them with the new
|
||||
// upstream interface. If upstream is a virtual network, treated as no upstream.
|
||||
if (prevUpstreamIfindex != upstreamIfindex) {
|
||||
if (prevUpstreamIfindex != upstreamIfindex
|
||||
|| !prevUpstreamPrefixes.equals(upstreamPrefixes)) {
|
||||
mBpfCoordinator.updateAllIpv6Rules(this, this.mInterfaceParams,
|
||||
getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf));
|
||||
getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf),
|
||||
upstreamPrefixes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1371,7 +1376,7 @@ public class IpServer extends StateMachineShim {
|
||||
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
|
||||
mUpstreamIfaceSet = null;
|
||||
mBpfCoordinator.updateAllIpv6Rules(
|
||||
IpServer.this, IpServer.this.mInterfaceParams, NO_UPSTREAM);
|
||||
IpServer.this, IpServer.this.mInterfaceParams, NO_UPSTREAM, Set.of());
|
||||
}
|
||||
|
||||
private void cleanupUpstreamInterface(String upstreamIface) {
|
||||
@@ -1548,4 +1553,21 @@ public class IpServer extends StateMachineShim {
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
/** Get IPv6 prefixes from LinkProperties */
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
static HashSet<IpPrefix> getTetherableIpv6Prefixes(@NonNull Collection<LinkAddress> addrs) {
|
||||
final HashSet<IpPrefix> prefixes = new HashSet<>();
|
||||
for (LinkAddress linkAddr : addrs) {
|
||||
if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
|
||||
prefixes.add(new IpPrefix(linkAddr.getAddress(), RFC7421_PREFIX_LENGTH));
|
||||
}
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private HashSet<IpPrefix> getTetherableIpv6Prefixes(@NonNull LinkProperties lp) {
|
||||
return getTetherableIpv6Prefixes(lp.getLinkAddresses());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import static android.system.OsConstants.ETH_P_IP;
|
||||
import static android.system.OsConstants.ETH_P_IPV6;
|
||||
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV4_MIN_MTU;
|
||||
import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN;
|
||||
import static com.android.net.module.util.ip.ConntrackMonitor.ConntrackEvent;
|
||||
import static com.android.networkstack.tethering.BpfUtils.DOWNSTREAM;
|
||||
import static com.android.networkstack.tethering.BpfUtils.UPSTREAM;
|
||||
@@ -90,7 +91,6 @@ import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -123,7 +123,6 @@ public class BpfCoordinator {
|
||||
private static final int DUMP_TIMEOUT_MS = 10_000;
|
||||
private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString(
|
||||
"00:00:00:00:00:00");
|
||||
private static final IpPrefix IPV6_ZERO_PREFIX64 = new IpPrefix("::/64");
|
||||
private static final String TETHER_DOWNSTREAM4_MAP_PATH = makeMapPath(DOWNSTREAM, 4);
|
||||
private static final String TETHER_UPSTREAM4_MAP_PATH = makeMapPath(UPSTREAM, 4);
|
||||
private static final String TETHER_DOWNSTREAM6_FS_PATH = makeMapPath(DOWNSTREAM, 6);
|
||||
@@ -768,7 +767,8 @@ public class BpfCoordinator {
|
||||
* Note that this can be only called on handler thread.
|
||||
*/
|
||||
public void updateAllIpv6Rules(@NonNull final IpServer ipServer,
|
||||
final InterfaceParams interfaceParams, int newUpstreamIfindex) {
|
||||
final InterfaceParams interfaceParams, int newUpstreamIfindex,
|
||||
@NonNull final Set<IpPrefix> newUpstreamPrefixes) {
|
||||
if (!isUsingBpf()) return;
|
||||
|
||||
// Remove IPv6 downstream rules. Remove the old ones before adding the new rules, otherwise
|
||||
@@ -791,9 +791,11 @@ public class BpfCoordinator {
|
||||
|
||||
// Add new upstream rules.
|
||||
if (newUpstreamIfindex != 0 && interfaceParams != null && interfaceParams.macAddr != null) {
|
||||
addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
|
||||
newUpstreamIfindex, interfaceParams.index, IPV6_ZERO_PREFIX64,
|
||||
interfaceParams.macAddr, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS));
|
||||
for (final IpPrefix ipPrefix : newUpstreamPrefixes) {
|
||||
addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
|
||||
newUpstreamIfindex, interfaceParams.index, ipPrefix,
|
||||
interfaceParams.macAddr, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS));
|
||||
}
|
||||
}
|
||||
|
||||
// Add updated downstream rules.
|
||||
@@ -1256,10 +1258,24 @@ public class BpfCoordinator {
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
private IpPrefix longToPrefix(long ip64) {
|
||||
final ByteBuffer prefixBuffer = ByteBuffer.allocate(IPV6_ADDR_LEN);
|
||||
prefixBuffer.putLong(ip64);
|
||||
IpPrefix sourcePrefix;
|
||||
try {
|
||||
sourcePrefix = new IpPrefix(InetAddress.getByAddress(prefixBuffer.array()), 64);
|
||||
} catch (UnknownHostException e) {
|
||||
// Cannot happen. InetAddress.getByAddress can only throw an exception if the byte array
|
||||
// is the wrong length, but we allocate it with fixed length IPV6_ADDR_LEN.
|
||||
throw new IllegalArgumentException("Invalid IPv6 address");
|
||||
}
|
||||
return sourcePrefix;
|
||||
}
|
||||
|
||||
private String ipv6UpstreamRuleToString(TetherUpstream6Key key, Tether6Value value) {
|
||||
return String.format("%d(%s) [%s] -> %d(%s) %04x [%s] [%s]",
|
||||
key.iif, getIfName(key.iif), key.dstMac, value.oif, getIfName(value.oif),
|
||||
value.ethProto, value.ethSrcMac, value.ethDstMac);
|
||||
return String.format("%d(%s) [%s] [%s] -> %d(%s) %04x [%s] [%s]",
|
||||
key.iif, getIfName(key.iif), key.dstMac, longToPrefix(key.src64), value.oif,
|
||||
getIfName(value.oif), value.ethProto, value.ethSrcMac, value.ethDstMac);
|
||||
}
|
||||
|
||||
private void dumpIpv6UpstreamRules(IndentingPrintWriter pw) {
|
||||
@@ -1309,8 +1325,8 @@ public class BpfCoordinator {
|
||||
// TODO: use dump utils with headerline and lambda which prints key and value to reduce
|
||||
// duplicate bpf map dump code.
|
||||
private void dumpBpfForwardingRulesIpv6(IndentingPrintWriter pw) {
|
||||
pw.println("IPv6 Upstream: iif(iface) [inDstMac] -> oif(iface) etherType [outSrcMac] "
|
||||
+ "[outDstMac]");
|
||||
pw.println("IPv6 Upstream: iif(iface) [inDstMac] [sourcePrefix] -> oif(iface) etherType "
|
||||
+ "[outSrcMac] [outDstMac]");
|
||||
pw.increaseIndent();
|
||||
dumpIpv6UpstreamRules(pw);
|
||||
pw.decreaseIndent();
|
||||
@@ -1554,8 +1570,7 @@ public class BpfCoordinator {
|
||||
*/
|
||||
@NonNull
|
||||
public TetherUpstream6Key makeTetherUpstream6Key() {
|
||||
byte[] prefixBytes = Arrays.copyOf(sourcePrefix.getRawAddress(), 8);
|
||||
long prefix64 = ByteBuffer.wrap(prefixBytes).order(ByteOrder.BIG_ENDIAN).getLong();
|
||||
long prefix64 = ByteBuffer.wrap(sourcePrefix.getRawAddress()).getLong();
|
||||
return new TetherUpstream6Key(downstreamIfindex, inDstMac, prefix64);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user