diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java index 898b124e07..4c9460b423 100644 --- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java +++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java @@ -17,6 +17,7 @@ package com.android.networkstack.tethering.apishim.api30; import android.net.INetd; +import android.net.IpPrefix; import android.net.MacAddress; import android.net.TetherStatsParcel; import android.os.RemoteException; @@ -81,14 +82,14 @@ public class BpfCoordinatorShimImpl @Override public boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, - @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac, - @NonNull MacAddress outDstMac, int mtu) { + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac, + @NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac, int mtu) { return true; } @Override - public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, - int upstreamIfindex, @NonNull MacAddress inDstMac) { + public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac) { return true; } diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java index 3cad1c665a..062ecc5168 100644 --- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java +++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java @@ -17,7 +17,9 @@ package com.android.networkstack.tethering.apishim.api31; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; +import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; +import android.net.IpPrefix; import android.net.MacAddress; import android.system.ErrnoException; import android.system.Os; @@ -48,6 +50,9 @@ import com.android.networkstack.tethering.TetherUpstream6Key; import java.io.FileDescriptor; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; /** * Bpf coordinator class for API shims. @@ -196,13 +201,23 @@ public class BpfCoordinatorShimImpl return true; } + @NonNull + private TetherUpstream6Key makeUpstream6Key(int downstreamIfindex, @NonNull MacAddress inDstMac, + @NonNull IpPrefix sourcePrefix) { + byte[] prefixBytes = Arrays.copyOf(sourcePrefix.getRawAddress(), 8); + long prefix64 = ByteBuffer.wrap(prefixBytes).order(ByteOrder.BIG_ENDIAN).getLong(); + return new TetherUpstream6Key(downstreamIfindex, inDstMac, prefix64); + } + @Override public boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, - @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac, - @NonNull MacAddress outDstMac, int mtu) { + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac, + @NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac, int mtu) { if (!isInitialized()) return false; + // RFC7421_PREFIX_LENGTH = 64 which is the most commonly used IPv6 subnet prefix length. + if (sourcePrefix.getPrefixLength() != RFC7421_PREFIX_LENGTH) return false; - final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex, inDstMac); + final TetherUpstream6Key key = makeUpstream6Key(downstreamIfindex, inDstMac, sourcePrefix); final Tether6Value value = new Tether6Value(upstreamIfindex, outSrcMac, outDstMac, OsConstants.ETH_P_IPV6, mtu); try { @@ -216,10 +231,12 @@ public class BpfCoordinatorShimImpl @Override public boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, - @NonNull MacAddress inDstMac) { + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac) { if (!isInitialized()) return false; + // RFC7421_PREFIX_LENGTH = 64 which is the most commonly used IPv6 subnet prefix length. + if (sourcePrefix.getPrefixLength() != RFC7421_PREFIX_LENGTH) return false; - final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfindex, inDstMac); + final TetherUpstream6Key key = makeUpstream6Key(downstreamIfindex, inDstMac, sourcePrefix); try { mBpfUpstream6Map.deleteEntry(key); } catch (ErrnoException e) { diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java index 51cecfe889..25fa8bc9d2 100644 --- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java +++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java @@ -16,6 +16,7 @@ package com.android.networkstack.tethering.apishim.common; +import android.net.IpPrefix; import android.net.MacAddress; import android.util.SparseArray; @@ -79,25 +80,27 @@ public abstract class BpfCoordinatorShim { * @param downstreamIfindex the downstream interface index * @param upstreamIfindex the upstream interface index + * @param sourcePrefix the source IPv6 prefix * @param inDstMac the destination MAC address to use for XDP * @param outSrcMac the source MAC address to use for packets * @param outDstMac the destination MAC address to use for packets * @return true if operation succeeded or was a no-op, false otherwise */ public abstract boolean startUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, - @NonNull MacAddress inDstMac, @NonNull MacAddress outSrcMac, - @NonNull MacAddress outDstMac, int mtu); + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac, + @NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac, int mtu); /** * Stops IPv6 forwarding between the specified interfaces. * @param downstreamIfindex the downstream interface index * @param upstreamIfindex the upstream interface index + * @param sourcePrefix the valid source IPv6 prefix * @param inDstMac the destination MAC address to use for XDP * @return true if operation succeeded or was a no-op, false otherwise */ - public abstract boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, - int upstreamIfindex, @NonNull MacAddress inDstMac); + public abstract boolean stopUpstreamIpv6Forwarding(int downstreamIfindex, int upstreamIfindex, + @NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac); /** * Return BPF tethering offload statistics. diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java index 976f5df143..f22ccbd132 100644 --- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java +++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -37,6 +37,7 @@ import static com.android.networkstack.tethering.util.TetheringUtils.getTetherin import android.app.usage.NetworkStatsManager; import android.net.INetd; +import android.net.IpPrefix; import android.net.LinkProperties; import android.net.MacAddress; import android.net.NetworkStats; @@ -119,6 +120,7 @@ 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); @@ -615,8 +617,9 @@ public class BpfCoordinator { final int upstream = rule.upstreamIfindex; // TODO: support upstream forwarding on non-point-to-point interfaces. // TODO: get the MTU from LinkProperties and update the rules when it changes. - if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream, rule.srcMac, - NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, NetworkStackConstants.ETHER_MTU)) { + if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream, + IPV6_ZERO_PREFIX64, rule.srcMac, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, + NetworkStackConstants.ETHER_MTU)) { mLog.e("Failed to enable upstream IPv6 forwarding from " + getIfName(downstream) + " to " + getIfName(upstream)); } @@ -657,7 +660,7 @@ public class BpfCoordinator { final int downstream = rule.downstreamIfindex; final int upstream = rule.upstreamIfindex; if (!mBpfCoordinatorShim.stopUpstreamIpv6Forwarding(downstream, upstream, - rule.srcMac)) { + IPV6_ZERO_PREFIX64, rule.srcMac)) { mLog.e("Failed to disable upstream IPv6 forwarding from " + getIfName(downstream) + " to " + getIfName(upstream)); } diff --git a/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java b/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java index 5893885a76..36a1c3c3ec 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java +++ b/Tethering/src/com/android/networkstack/tethering/TetherUpstream6Key.java @@ -29,13 +29,17 @@ public class TetherUpstream6Key extends Struct { @Field(order = 0, type = Type.S32) public final int iif; // The input interface index. - @Field(order = 1, type = Type.EUI48, padding = 2) + @Field(order = 1, type = Type.EUI48, padding = 6) public final MacAddress dstMac; // Destination ethernet mac address (zeroed iff rawip ingress). - public TetherUpstream6Key(int iif, @NonNull final MacAddress dstMac) { + @Field(order = 2, type = Type.S64) + public final long src64; // The top 64-bits of the source ip. + + public TetherUpstream6Key(int iif, @NonNull final MacAddress dstMac, long src64) { Objects.requireNonNull(dstMac); this.iif = iif; this.dstMac = dstMac; + this.src64 = src64; } } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 46e50ef835..464778f93e 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -985,7 +985,7 @@ public class IpServerTest { throws Exception { if (!mBpfDeps.isAtLeastS()) return; final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index, - TEST_IFACE_PARAMS.macAddr); + TEST_IFACE_PARAMS.macAddr, 0); final Tether6Value value = new Tether6Value(upstreamIfindex, MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS, ETH_P_IPV6, NetworkStackConstants.ETHER_MTU); @@ -996,7 +996,7 @@ public class IpServerTest { throws Exception { if (!mBpfDeps.isAtLeastS()) return; final TetherUpstream6Key key = new TetherUpstream6Key(TEST_IFACE_PARAMS.index, - TEST_IFACE_PARAMS.macAddr); + TEST_IFACE_PARAMS.macAddr, 0); verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(key); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java index 4f32f3c216..8bc4c182a4 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -641,7 +641,7 @@ public class BpfCoordinatorTest { private void verifyStartUpstreamIpv6Forwarding(@Nullable InOrder inOrder, int downstreamIfIndex, MacAddress downstreamMac, int upstreamIfindex) throws Exception { if (!mDeps.isAtLeastS()) return; - final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac); + final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac, 0); final Tether6Value value = new Tether6Value(upstreamIfindex, MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS, ETH_P_IPV6, NetworkStackConstants.ETHER_MTU); @@ -652,7 +652,7 @@ public class BpfCoordinatorTest { MacAddress downstreamMac) throws Exception { if (!mDeps.isAtLeastS()) return; - final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac); + final TetherUpstream6Key key = new TetherUpstream6Key(downstreamIfIndex, downstreamMac, 0); verifyWithOrder(inOrder, mBpfUpstream6Map).deleteEntry(key); } @@ -2192,7 +2192,7 @@ public class BpfCoordinatorTest { mBpfDownstream6Map.insertEntry(rule.makeTetherDownstream6Key(), rule.makeTether6Value()); final TetherUpstream6Key upstream6Key = new TetherUpstream6Key(DOWNSTREAM_IFINDEX, - DOWNSTREAM_MAC); + DOWNSTREAM_MAC, 0); final Tether6Value upstream6Value = new Tether6Value(UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS, ETH_P_IPV6, NetworkStackConstants.ETHER_MTU); diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c index 8645dd7874..c752779c64 100644 --- a/bpf_progs/offload.c +++ b/bpf_progs/offload.c @@ -194,6 +194,7 @@ static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool TetherUpstream6Key ku = { .iif = skb->ifindex, + .src64 = 0, }; if (is_ethernet) __builtin_memcpy(downstream ? kd.dstMac : ku.dstMac, eth->h_dest, ETH_ALEN); diff --git a/bpf_progs/offload.h b/bpf_progs/offload.h index 9dae6c9879..1e28f01f7c 100644 --- a/bpf_progs/offload.h +++ b/bpf_progs/offload.h @@ -135,10 +135,10 @@ STRUCT_SIZE(TetherDownstream64Value, 4 + 14 + 2 + 4 + 4 + 2 + 2 + 8); // 40 typedef struct { uint32_t iif; // The input interface index uint8_t dstMac[ETH_ALEN]; // destination ethernet mac address (zeroed iff rawip ingress) - uint8_t zero[2]; // zero pad for 8 byte alignment - // TODO: extend this to include src ip /64 subnet + uint8_t zero[6]; // zero pad for 8 byte alignment + uint64_t src64; // Top 64-bits of the src ip } TetherUpstream6Key; -STRUCT_SIZE(TetherUpstream6Key, 12); +STRUCT_SIZE(TetherUpstream6Key, 4 + 6 + 6 + 8); // 24 typedef struct { uint32_t iif; // The input interface index