From c8fb1a2530662adc9ec5d6282a6fd47cbe18fcd2 Mon Sep 17 00:00:00 2001 From: KH Shi Date: Tue, 8 Aug 2023 15:30:45 +0800 Subject: [PATCH] bpf tethering offload - add src subnet to upstream ipv6 direction This patch is based on aosp/2535559 from maze@. Add source prefix into the upstream key such that only packets which source IPv6 address matches it will be forwarded to the upstream interface. In this patch, the source prefix is set to zero so there is no behavior changes. Next CL in patch series will use the real source prefixes retrieved from upstream interface. Test: atest TetheringTests Bug: 261923493 Change-Id: I43d068a29b937c7dfeb6fab632a8effb47ee2263 --- .../apishim/api30/BpfCoordinatorShimImpl.java | 9 ++++--- .../apishim/api31/BpfCoordinatorShimImpl.java | 27 +++++++++++++++---- .../apishim/common/BpfCoordinatorShim.java | 11 +++++--- .../tethering/BpfCoordinator.java | 9 ++++--- .../tethering/TetherUpstream6Key.java | 8 ++++-- .../unit/src/android/net/ip/IpServerTest.java | 4 +-- .../tethering/BpfCoordinatorTest.java | 6 ++--- bpf_progs/offload.c | 1 + bpf_progs/offload.h | 6 ++--- 9 files changed, 55 insertions(+), 26 deletions(-) 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